(1)初始化函数: int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);
每一个使用Windows Socket的应用程序都必须使用WSAStartup函数。
参数1:表示使用Windows Sockets API的版本:这是一个WORD类型的整数,它的高位字节定义是次版本号,低位定义的是主版本号。
参数2:指向WSADATA资料的指针。
返回值:成功返回0.
失败返回如下可能。
WSASYSNOTREADY:表示网络设备没有准备好。
WSAVERNOTSUPPORTED:Winsock的版本信息号不支持。
WSAEINPROGRESS:一个阻塞的Winsock1.1存在于进程中。
WSAEPROCLIM:已经达到Winsock使用量上限。
WSAEFAULT:lpWSAData不是一个有效的指针。
(2)创建一个socket:
SOCKET socket(int af,int type,int protocol);
参数1:指地址族。一般都填AF_INET,表示IPV4地址族
参数2:类型包括流连接(SOCK_STREAM)和数据报连接(SOCK_DGRAM),分别对应TCP协议和UDP协议
参数3:一般为0.表示对两种类型分别采用缺省的TCP和UDP传输协议。
返回值:是由Winsock定义的一种数据类型SOCKET,它实际上是一个整形数据,在socket创建成功时,代表Winsock分配给程序的socket编号,后面调用传递函数时,就可以把它像文件指针一样引用。
(3)创建的函数指定通信对象:int bind(SOCKET s,struct sockaddr_in*name,int namelen);
参数1:是创建好的套接字。
参数2:是描述通信对象地址信息的结构体指针。
参数3:该结构体的长度。
sockaddr_in定义如下:
struct sockaddr_in{
short sin_family;//地址协议族,通常是AF_INET
unsigned short sin_port;//端口号
struct in_addr sin_addr;//IP地址
char sin_zero[8];//添加这个长度,使sockaddr_in的长度为16字节,以便操作
};
IP地址sin_addr结构:
struct sin_addr{
union {
struct{
unsigned char s_b1,
s_b2,
s_b3,
s_b4;
}s_un_b;
struct{
unsigned short s_w1,s_w2;
}S_un_w;
unsigned long S_addr;
}S_un;
};
例如一个IP地址“10.14.25.90”
M1:
sin_addr.S_un.S_un_b.s_b1=10
sin_addr.S_un.S_un_b.s_b2=14
sin_addr.S_un.S_un_b.s_b3=25
sin_addr.S_un.S_un_b.s_b4=90
M2:
sin_addr.S_un.S_un_w.s_w1=(14<<8)|10
sin_addr.S_un.S_un_w.s_w2=(90<<8)|25
M3:
Sin_addr.S_un.S_addr=(90<<24)|(25<<16)|(14<<8)|10
(4)设置等待连接状态
int listen(SOCKET s,int backlog);
backlog是等待队列的长度。
(5)接受连接请求
SOCKET accept(SOCKET s,struct sockaddr_in *addr,int *addrlen);
accept在接收到连接请求后,会为这个连接建立一个新的socket来与对方通信,并把它作为返回值。新建的SOCKET和原来的SOCKET具有相同的特性。
原来的SOCKET被释放,用于继续等待其他的连接请求。而新生的SOCKET才是与客户端进行实际通信的Socket。所以一般将参数中的Socket成为“监听Socket”,将新生成的SOCKET叫做“回话Socket”,他只负责与客户端通话。通过addr可得到客户机的IP地址和连接的端口号。
(6)对于客户程序要主动提出连接请求,应使用connect函数。
int connect(SOCKET s,struct sockaddr_in *name,int namelen);
如果失败,返回SOCKET_ERROR
(7)send()/recv():发送和接收数据。
int send(SOCKET s,char *buf,int len,int flags);
int recv(SOCKET s,char *buf,int len,int flags);
flags一般取0.recv函数实际上是接收send函数发过来的数据包。当读到的数据字节少于规定接受的数目时,就把数据全部接受。并返回实际接收的字节数。当读到的数据多余规定的数目时,在流方式下,剩余的数据由下一个recv函数读出,在数据报方式下,数据将被丢弃。这两个函数在出错时都返回SOCKET_ERROR.
以数据报方式通信的Socket,由于事先不用连接,所以可以跳过connect函数,而直接用recvfrom和sendto
int recvfrom(SOCKET s,char *buf,int len,int flags,struct sockaddr_in from,int *fromlen);
int sendto(SOCKET s,char *buf,int len,int fags,struct sockaddr_in to,int *tolen);
(8)关闭socket。
closesocket(SOCKET s);