學習網絡編程的一些實用技巧和細節
阿新 • • 發佈:2019-03-03
學習 rtt cso htons details etl str art linu
https://blog.csdn.net/analogous_love/article/details/60761528
一、非阻塞的的connect()函數如何編寫
1. 創建socket時,將socket設置成非阻塞模式
2. 接著調用connect()進行連接,如果connect()能立即連接成功,則返回0;如果此刻不能立即連接成功,則返回-1(windows上返回SOCKET_ERROR也等於-1),這個時候錯誤碼是WSAEWOULDBLOCK(windows平臺),或者是EINPROGRESS(linux平臺),表明立即暫時不能完成。
3. 接著調用select()函數在指定的時間內檢測socket是否可寫,如果可寫表明connect()連接成功。
需要註意的是:linux平臺上connect()暫時不能完成返回-1,錯誤碼可能是EINPROGRESS,也可能是由於被信號給中斷了,這個時候錯誤碼是:EINTR。這種情況也要考慮到;而在windows平臺上除了用select()函數去檢測socket是否可寫,也可以使用windows平臺自帶的函數WSAAsyncSelect或WSAEventSelect來檢測。
/** *@param timeout 連接超時時間,單位為秒 *@return 連接成功返回true,反之返回false **/ bool CSocket::Connect(int timeout) {//windows將socket設置成非阻塞的方式 unsigned long on = 1; if (::ioctlsocket(m_hSocket, FIONBIO, &on) < 0) return false; //linux將socket設置成非阻塞的方式 //將新socket設置為non-blocking /* int oldflag = ::fcntl(newfd, F_GETFL, 0); int newflag = oldflag | O_NONBLOCK; if (::fcntl(m_hSocket, F_SETFL, newflag) == -1) return false;*/ struct sockaddr_in addrSrv = { 0 }; addrSrv.sin_family = AF_INET; addrSrv.sin_addr = htonl(addr); addrSrv.sin_port = htons((u_short)m_nPort); int ret = ::connect(m_hSocket, (struct sockaddr*)&addrSrv, sizeof(addrSrv)); if (ret == 0)//返回0 直接ok了 return true; //windows下檢測WSAEWOULDBLOCK if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK) return false; //linux下需要檢測EINPROGRESS和EINTR /* //小於0 需要進行錯誤碼的檢驗 因為已經發起了三次握手 需要時間呢 RTT時間的存在 所以後面需要select再次進行檢驗 if (ret < 0 && (errno != EINPROGRESS || errno != EINTR)) return false; */ fd_set writeset; FD_ZERO(&writeset); FD_SET(m_hSocket, &writeset); struct timeval tv; tv.tv_sec = timeout; //可以利用tv_usec做更小精度的超時設置 tv.tv_usec = 0; if (::select(m_hSocket + 1, NULL, &writeset, NULL, &tv) != 1) return false; return true; }
二、非阻塞socket下如何正確的收發數據
繼續未完成
學習網絡編程的一些實用技巧和細節