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函數意圖在多線程進程中提供線程安全的方式。