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