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函数意图在多线程进程中提供线程安全的方式。