Windows Programming/Winsock
与Berkeley socket的差别
[编辑]windows与linux平台使用的socket均继承自Berkeley socket(rfc3493),都支持select I/O模型,均支持使用getaddrinfo与getnameinfo实现协议无关编程。 但存在细微差别,
头文件, Linux要包含
#include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h>
而windows下则是包含
#include <winsock2.h> (需要在windows.h前包含),并要链接库ws2_32.lib
获取错误码 windows下getlasterror() / WSAGetLastError()。linux下用<errno.h>声明的errno变量
Linux中socket为整形,Windows中为一个SOCKET结构类型。
Linux中关闭socket为close,Windows中为closesocket。
send*与recv*函数参数之socket长度的类型, Linux中类型socklen_t,Windows中直接为int。可用宏处理这一差异: 用到的一些宏:
#ifdef WIN32 typedef int socklen_t; typedef int ssize_t; #endif #ifdef __LINUX__ typedef int SOCKET; typedef unsigned char BYTE; typedef unsigned long DWORD; #define FALSE 0 #define SOCKET_ERROR (-1) #endif
windows下在使用socket之前与之后要分别使用WSAStartup与WSAClean。
select函数第一个参数,windows忽略该参数,linux下该参数表示集合中socket的上限值,一般设为sockfd(需select的socket) + 1。
因为linux中的socket与普通的文件描述符fd一样,所以可以在TCP的socket中,发送与接收数据时,直接使用read和write。而windows只能使用recv和send。
windows下socket函数返回值类型为SOCKET(unsigned int),其中发生错误时返回INVALID_SOCKET(0),linux下socket函数返回值类型int, 发生错误时返回 - 1。
如果绑定本机回环地址,windows下sendto函数可以通过,linux下sendto报错:errno = 22, Invalid arguement。一般情况下均绑定通配地址。
send函数最后一个参数 : windows下一般设置为0; linux下最好设置为MSG_NOSIGNAL,如果不设置,在发送出错后有可 能会导致程序退出。
设置socet选项,如设置socket为非阻塞的。 Linux下为 <fcntl.h>
flag = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flag | O_NONBLOCK);
Windows下为
flag = 1; ioctlsocket(fd, FIONBIO, (unsigned long *)&flag);
当非阻塞socket的TCP连接正在进行时,Linux的错误号为EINPROGRESS,Windows的错误号为WSAEWOULDBLOCK。
释放Winsock库
[编辑]WSACleanup函数将清除已经加载的Winsock资源,这将造成同进程下其他线程使用WinSock的失败返回。
错误处理
[编辑]大部分Windows Sockets 2函数返回时不会一并返回出错原因。某些Winsock函数成功调用则返回0值,出错时返回值SOCKET_ERROR (-1);返回句柄的Winsock函数出错时返回值INVALID_SOCKET (0xffff);返回指针的Winsock函数出错时返回值 NULL;用WSAGetLastError函数可查到出错号。 WSAGetLastError函数代替了Windows API的GetLastError函数。Windows Socket的错误码类似于UNIX socket错误码常量,但这些常量加了前缀WSA。因此Winsock应用程序返回的错误码WSAEWOULDBLOCK,对应于UNIX程序返回的错误码EWOULDBLOCK。
Windows Socket设置的错误码不能通过变量errno访问。getXbyY系列函数的错误码不能通过变量h_errno访问。WSAGetLastError函数意图在多线程进程中提供线程安全的方式。