最近看了許多關於網絡編程的資料,自己小記一下,以方便以后查找。
什么是阻塞socket,什么是非阻塞socket。對於這個問題,我們要先弄清什么是阻塞/非阻塞。阻塞與非阻塞是對一個文件描述符指定的文件或設備的兩種工作方式。 阻塞的意思是指,當試圖對該文件描述符進行讀寫時,如果當時沒有東西可讀或者暫時不可寫,程序就進入等待狀態,直到有東西可讀或者可寫為止。 非阻塞的意思是,當沒有東西可讀或者不可寫時,讀寫函數就馬上返回,而不會等待。
這里我列舉了,哪些socket api會阻塞:
accept,connect,recv(recvfrom),send(sendto),closesocket,select(poll或epoll)
1)accept在阻塞模式下,沒有新連接時,線程會進入睡眠狀態;非阻塞模式下,沒有新連接時,立即返回WOULDBLOCK錯誤。
2)connect在阻塞模式下,僅TCP連接建立成功或出錯時才返回,分幾種具體的情況,這里不再敘述;非阻塞模式下,該函數會立即返回INPROCESS錯誤(需用select檢測該連接是否建立成功)
3)recv/recvfrom/send/sendto很好理解,因為這兩類函數讀寫socket文件描述符的接收/發送緩沖區。
4) select/poll/epoll並不是真正意義上的阻塞,它們的阻塞是由於它們最后一個timeout參數決定的,timeout大於0時,它們會一直等待直到超時才退出(相等於阻塞了吧,^_^),而timeout=-1即永遠等待。
5)closesocket也不是真正意義上的阻塞,它其實是指是否等待關閉(相當於阻塞了吧,^_^),它受套接字選項SO_LINGER和SO_DONTLINGER的影響。
若SO_DONTLINGER或SO_LINGER的間隔=0時,closesocket就是非等待關閉的,但是當SO_LINGER的間隔>0時,closesoket就是等待關閉的,直到剩余數據都發送完畢或直到超時才退出。
(但是這個地方只有對於阻塞的套接口才有用,如果是非阻塞的套接口,它會立即返回並且指示錯誤WOULDBLOCK)。
實例:
客戶端讀操作:
1 BOOL CCommunication::InitCom() 2 { 3 WORD wVersionRequested; 4 WSADATA wsaData; 5 int err; 6 CString szMsg; 7 m_tcpPort.TrimLeft(); 8 m_tcpPort.TrimRight(); 9 10 int port = atoi(m_tcpPort); 11 12 wVersionRequested = MAKEWORD(1,1); 13 14 err = WSAStartup(wVersionRequested,&wsaData); 15 if (err != 0) 16 { 17 return FALSE; 18 } 19 20 if (LOBYTE(wsaData.wVersion) != 1 || 21 HIBYTE(wsaData.wVersion) != 1) 22 { 23 WSACleanup(); 24 return FALSE; 25 } 26 27 m_clientSocket = socket(AF_INET,SOCK_STREAM,0); 28 if (m_clientSocket == INVALID_SOCKET) 29 { 30 TRACE("創建套接字失敗!"); 31 return FALSE; 32 } 33 34 SOCKADDR_IN addrClient; 35 addrClient.sin_addr.S_un.S_addr = inet_addr(m_szLocalPort); 36 addrClient.sin_family = AF_INET; 37 addrClient.sin_port = htons(port); 38 memset(addrClient.sin_zero,0,sizeof(addrClient.sin_zero)); 39 m_connsocket = connect(m_clientSocket,(SOCKADDR*)&addrClient,sizeof(SOCKADDR)); 40 if (m_connsocket == SOCKET_ERROR) 41 { 42 TRACE("Connect Error!"); 43 return FALSE; 44 } 45 DWORD nMode = 1; 46 int nError = ioctlsocket(m_clientSocket,FIONBIO,&nMode); 47 if (nError == SOCKET_ERROR) 48 { 49 closesocket(m_clientSocket); 50 WSACleanup(); 51 return FALSE; 52 } 53 return TRUE; 54 } 55 56 int CCommunication::ReadBytes(BYTE *lpByte, DWORD dwBytes) 57 { 58 tv.tv_sec = 2; 59 tv.tv_usec = 0; 60 FD_ZERO(&fdRead); 61 FD_SET(m_clientSocket,&fdRead); 62 63 int nError = select(0,&fdRead,NULL,NULL,&tv); 64 if (nError <= 0) 65 { 66 return 0; 67 } 68 if (FD_ISSET(m_clientSocket,&fdRead)) 69 { 70 memset(lpByte,0,dwBytes); 71 nError = recv(m_clientSocket,(char*)lpByte,dwBytes,0); 72 } 73 74 75 return nError; 76 }