Windows socket编程基础
一、Winsock初始化
在进行winsock编程前需要进行初始化,调用WSAStartup函数,设置当前的winsock的版本和初始化相对应版本的库。
1 |
|
- wVersionRequested:当前所使用的winsock版本信息。使用MAKEWORD()函数,产生一个版本号,副版本号为高位,主版本号为低位,如版本号为2.1,则MAKEWORD(1,2),返回0x0102。
- lpWSAData:WSAData结构体变量指针
- return:0成功,非0失败
当要注销该库时使用函数WSACleanup(void);,成功返回0,失败返回SOCKET_ERROR。
二、数据类型之间的转换
网络与本低字节序的转换
在计算机当中,根据cpu或操作系统的不同可分为大端存储(Big Endian)和小端存储(Little Endian)。
大端存储:高位字节存放到地位地址
小端存储:高位字节存放到高位地址
字节序转换函数
1 | unsigned short htos(unsigned short); |
h代表主机(host)字节序,n代表网络(network)字节序。
在windows平台下,大部分采用大端法,但是在网络中以小端法方式传输,所以在接收时要进行字节序的转换。
字符串跟IP地址之间的转换
从字符串转换到IP
在SOCKADDR_IN的sin_addr中保存的是32位整数型,而人为添加的IP是一个点分十进制字符串,所以需要通过转换才能使IP地址被传递到SOCKADDR_IN的变量中。这就是所谓的网络字节序的转换。
1 | //windows platform |
- return:成功时返回32位小端(或大端)序整数,失败返回INADDR_NONE
从IP转换到字符串
有时候需要获取到从网络当中获得的IP地址并通过点分十进制显示出来。在Windows平台上只有inet_ntoa(),没有inet_aton()。
1 | //windows platform |
- in:具有整型IP地址的in_addr变量。
- return:成功返回地址字符串,失败返回-1。
示例
1 | /*inet_addr用例*/ |
WinSock2自带转换函数
WSAStringToAddress&WSAAddressToString,这两个转换函数功能跟inet_ntoa,inet_addr一致,支持IPv4和IPv6,但是不支持跨平台,兼容性差。
WSAStringToAddress
1 |
|
- AddressString:含有端口号和ip的字符串。
- AddressFamily:地址协议族。
- lpProtocolInfo:设置协议提供者,默认为NULL。
- lpAddress:保存地址信息的SOCKADDR变量。
- lpAddressLength:lpAddress长度的指针。
- return:成功返回0,失败返回SOCKET_ERROR。
WSAAddressToString
1 | INT WSAAddressToString( |
- lpsaAddress:需要转换的地址信息的SOCKADDR变量。
- dwAddressLength:lpsaAddress长度的指针。
- lpProtocolInfo:设置协议提供者,默认为NULL。
- lpszAddressString:保存转换结果的字符串。
- lpdwAddressStringLength:lpszAddressString存有地址信息的长度。
示例
1 | /*WSAStringToAddress用例*/ |
三、Windows socket相关函数
连接相关的函数都在WinSock2.h中.
1 | SOCKET socket(int af, int type, int protocol); |
- af:协议族,IPv4(AF_INET)或IPv6
- type:socket类型,SOCK_STREAM, SOCKET_DGRAM, SOCK_RAW
- protocol:socket使用的特定协议,默认为0
- return:成功返回套接字句柄,失败返回INVALID_SOCKET
1 | int bind(SOCKET s, const struct sockaddr * name, int namelen); |
- s:socket返回的套接字
- name:SOCKADDR类型的指针,可以通过强制类型转换,将SOCKADDR_IN转成SOCKADDR。
- namelen:name的长度。
- return:成功返回0,失败返回SOCKET_ERROR
1 | int listen(SOCKET s, int backlog); |
- s:socket返回的套接字
- backlog:请求连接队列的最大长度。
1 | int accept(SOCKET s, struct sockaddr *addr, int *addrlen); |
- s:socket返回的套接字
- addr:SOCKADDR类型的指针,可以通过强制类型转换,将SOCKADDR_IN转成SOCKADDR。
- addrlen:addr的长度。
- return:成功返回指向客户端的套接字,失败返回INVALID_SOCKET
1 | int connect(SOCKET s, const struct sockaddr *name, int namelen); |
- s:socket返回的套接字
- name:SOCKADDR类型的指针,可以通过强制类型转换,将SOCKADDR_IN转成SOCKADDR。
- namelen:name的长度。
- return:成功返回0,失败返回SOCKET_ERROR
1 | int closesocket(SOCKET s); |
- s:要断开的socket套接字
return:成功返回0,失败返回SOCKET_ERROR。
1
int shutdonw(SOCKET s, int how);
s:要断开的socket套接字
- how:断开方式。SD_RECEIVE:断开输入流;SD_SEND:断开输出流;SD_BOTH:同时断开I/O流。
- return:成功返回0,失败返回SOCKET_ERROR。
TCP数据传输I/O函数
1 | int send(SOCKET s, const char *buf, int len, int flags); |
- s:socket返回的套接字
- buf:发送的数据内容
- len:发送数据的最大长度
- flags:标识,默认0即可
- return:发送成功返回发送个数
1 | int recv(SOCKET s, const char *buf, int len, int flags); |
- s:socket返回的套接字
- buf:接收数据存放的数组
- len:接收数据的最大长度
- flags:标识,默认0即可
- return:接收成功返回实际接收个数
UDP数据传输I/O函数
UDP连接不需要确认就可以直接发送数据
1 |
|
- s:socket返回的套接字
- buf:待发送数据内容
- len:待传输的数据长度,以字节为单位
- flags:标识,默认0即可
- to:存有目标地址的SOCKADDR结构体变量地址值
- tolen:to地址值结构体变量长度
- return:成功返回传输字节数,失败返回-1
1 | int recvfrom(SOCKET s, const char * buf, int len, int flags, const struct sockaddr * from, int *fromlen); |
- s:socket返回的套接字
- buf:待接收数据的数组
- len:可接受的数据的最大长度
- flags:标识,默认0即可
- from:存有发送端地址的SOCKADDR结构体变量地址值
- fromlen:from地址值结构体变量指针长度
- return:成功返回传输字节数,失败返回-1