您的位置:首页 > 职场人生

创建套接字,面向连接通信

2012-03-06 21:48 399 查看
套接字是传输提供程序的句柄,是一个独立类型,SOCKET类型

socket WSASocket这两个函数可以用来创建套接字

SOCKET socket(
int af,
int type,
int protocol
);


服务器API函数

1.绑定 bind

一旦创建了某种协议的套接字,必须将套接字绑定到一个已知的地址

int bind(
SOCKET s,
const struct sockaddr FAR* name,
int   namelen
);
//s是等待客户连接的那个套接字

SOCKET s;
SOCKADDR_IN tcpaddr;
int port = 5050;

s = socket(AF_INET, SOCK_STREAM, IPPORTO_TCP);

tcpaddr.sin_family = AF_INET;
tcpaddr.sin_port = htons(port);
tcpaddr.sin_addr.s_addr = htonl(INADDR_ANY);

bind(s, (SOCKADDR *)&tcpaddr, sizeof(tcpaddr));

一旦出错,bind返回SOCKET_ERROR

2.监听 listen

接下来要做的是将套接字置于监听模式。

int listen(
SOCKET s;//被绑定的套接字
int backlog//指定了被搁置的连接最大队列长度
);


3.接收连接 accept

accept WSAAccept AcceptEx可以接受连接

SOCKET accept(
SOCKET s,//被绑定的套接字,它处于监听模式
struct sockaddr FAR* addr,//有效的SOCKADDR_IN地址
int FAR* addrlen//SOCKADDR_IN结构长度
);


编写一个能够接受TCP/IP连接的服务器

#include <winsock2.h>
void main(void)
{
WSAData wsaData;
SOCKET  ListenSocket;
SOCKET  NewSocket;
SOCKADDR_IN ServerAddr;
SOCKADDR_IN ClientAddr;
int port = 5050;
//初始化winsock版本
WSAStartup(MAKEWORD(2,2), &wsaData);

ListenSocket = socket(AF_INET, SOCK_STREAM, IPPORTO_TCP);
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(port);
ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);

bind(ListenSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr));

listen(ListenSocket, 5);

NewSocket = accept(ListenSocket, (SOCKADDR*)&ClientAddr, &ClientAddrLen);
//..

closesocket(NewSocket);
closesocket(ServerSocket);
WSACleanup();
}


客户端API函数

TCP状态:对每一个套接字来说,它的初始状态都是CLOSED。若客户机初始化一个连接就会向服务器发送一个SYN包,同时客户机将套接字状态置为SYN_SENT。服务器收到一个SYN包后,会发出一个SYN_ACK包,客户机需要发送一个ACK包对它作出响应。此时客户机将套接字处于ESTABLISHED状态,如果服务器一直不发送SYN_ACK包,客户机就会超时,并返回CLOSED状态。

若服务器的套接字同本地接口及端口绑定起来,并在上面进行监听,那么套接字状态就是LISTEN。客户机试图与服务器连接时,服务器就会收到一个SYN包,并用一个SYN_ACK包作为回应,服务器套接字状态就会变成SYN_RCVD,最好客户机发出一个ACK包,它将使服务器套接字置于ESTABLISHED状态。

一旦应用程序处于ESTABLISHED状态,就可以通过两种方法关闭它。如果是应用程序来关闭,便叫做主动套接字关闭;否则就是被动的。若主动关闭,应用程序会发出一个FIN包。应用程序调用closesocket或shutdown时,会向通信对方发出一个FIN包,而且套接字状态将变为FIN_WAIT_1。正常情况下,通信对方会用一个ACK包作为回应,套接字状态将变为FIN_WAIT_2。如果通信对方也关闭了连接,它会发出一个FIN包,我们的机器则会以一个ACK包作为回应,并将套接字状态置为TIME_WAIT。

被动关闭时,应用程序会从对方那里收到一个FIN包,并用一个ACK包作为回应,此时应用程序的套接字会变为CLOSE_WAIT状态。由于对方已经关闭自己,它不再发送数据。而应用程序却不同,它能一直发送数据,直到它自己关闭连接为止。要想连接终端,应用程序需要发出自己的FIN包,令应用程序套接字置于LAST_ACK,应用程序从对方接收到一个ACK包后,它的套接字就会变成CLOSEED状态。

connect

套接字连接通过调用connect,WSAConnect,ConnectEx函数来完成

int connect(
SOCKET s,//即将在上面建立连接的有效的TCP套接字
const struct sockaddr FAR* name,
int namelen
);


演示一个客户端:

#include <winsock2.h>

void main(void)
{
WSADATA wsaData;
SOCKET  s;
SOCKADDR_IN addr;
int port = 5050;

WSAStartup(MAKEWORD(2,2), &wsaData);
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr("123.123.123.123");
//...
connect(s, (SOCKADDR*)&addr, sizeof(addr));
closesocket(s);
WSACleanup();
}


数据传输

发送数据API send WSASend函数

接收数据API recv WSARecv函数

必须牢记着一点:所有关系到收发数据的缓冲区都属于简单的char类型,即面向字节的数据。

所有收发函数返回的错误都是SOCKET_ERROR,可以用WSAGetLastError来获得错误信息。

int send(
SOCKET s,//用于发送数据的套接字
const char FAR* buf,//指向字符数据的缓冲区指针,缓冲区中包含发送的数据
int len,//缓冲区内的字符数
int flags
);
//顺利的情况下,send将返回发送的字节数,若发送错误则返回SOCKET_ERRPR

int WSASend(
SOCKET s,//连接会话的套接字
LPWSABUF lpBuffer,//指向一个或多个WSABUF结构的指针
DWORD  dwBufferCount,//指明传递的WSABUF的数量
LPDWORD  lpNumberOfBytesSend,//指向DOWRD指针,其中包含已发送的字节总数
DWORD  dwFlags,
LPWSAOVERLAPPED lpOverLapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
//lpNumberOfBytesSend设为写入的字节数,执行成功是该函数返回0,否则返回SOCK_ERROR

发送函数 WSASendDisconnect

这个函数很特殊,一般不用

int WSASendDisconnect(
SOCKET s,
LPWSABUF lpOutboundDisconnectData
);

函数WSASendDisconnect起初将套接字置于关闭状态,并发送端口的数据

在建立连接的套接字上通过recv来接收数据

int recv(
SOCKET s,//准备用来接收数据的套接字
char FAR* buf,//用于接收数据的字符缓冲区
int len,//准备接受的字节数或者缓冲区的长度
int flags
);

尽量把所有的数据都复制到自己的缓冲区中,并在那里操作数据。

当挂起数据大于所提供的缓冲区时,缓冲区会尽量的让数据填满,这时,recv调用会产生WSAEMSGSIZE错误。注意,消息大小的错误是在面向消息的协议时发生,而流协议则把传入的数据缓存下来,并尽量返回应用程序所需要的数据,即使挂起的数据比提供的缓冲区大,因此对于流协议就不会碰到WSAEMSGSIZE错误。

int WSARecv(
SOCKET s,//建立连接的套接字
LPWSABUF lpBuffers,//用来接收数据的缓冲
DWORD dwBufferCount,
LPWORD lpNumberOfBytesRecvd, //指向这个函数调用从收到的字节数
LPWORD lpFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);


中断连接

一旦完成套接字连接,就必须关闭它,并释放关联到这个套接字上的所有资源。先用shutdown关闭连接,在利用closesocket释放关联到套接字上的资源。

int shutdown(
SOCKET s,
int  how
);
//how 可以是SD_RECEIVE,SD_SEND,SD_BOTH
//SD_RECEIVE表示不允许再调用接收函数
//SD_SEND表示不允许再调用发送函数
//SD_BOTH表示取消两端的收发操作

closesocket 用来关闭套接字

int closesocket(SOCKET s);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  职场 通信 休闲