標籤:
1.為什麼到現在才弄懂這個
不知道這個Socket重疊IO這種模型是不是socket IO完成連接埠的基礎,不過我感覺,學習一下這個再去學習socket IO完成連接埠是比較有好處的。
這個Scoket重疊IO我以前記得看過好幾次,都沒看懂。一部分原因是我沒能靜態心來寫代碼,還有更重要的原因就是,Socket重疊他們的結構體參數,還有傳參數讓人很難理解。下面我將對這些資料結構和參數進行一下講解
2.初識WSARecv 函數
int WSARecv( SOCKET s,//要接收訊息的socket LPWSABUF lpBuffers, //一個結構體數組。當接收IO操作完畢後接收內容就在這個裡面了 DWORD dwBufferCount, //要接多少個WSABUF LPDWORD lpNumberOfBytesRecvd,//接收了多少個位元組 LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped,//Overlapped結構體指標 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine//在本節用不用 );
lpBuffers參數:這是一WSABUF數組,意思是這個函數可以接收不止一個字元緩衝,但是我們一般用一個就夠了。 接收多個我還沒能測試
dwBufferCount參數:是指上一個參數的數組個數
lpOverlapped參數:這個參數是Overlappad結構體指標,這個指標當IO操作完畢的時候,這裡會被系統填充。當IO操作完成時這個結構也可以通過WSAGetOverlappedResult得到
傳回值:
0:沒有錯誤發生,IO操作當即完成
SOCKET_ERROR:發生錯誤
如果是SOCKET_ERROR並且WSAGetLastError() == WSA_IO_PENDING 這時表示操作已經提交。非同步作業大部分都是這樣的。
3.何時得到收取的訊息,然後取出訊息
當異常操作完成時,Overlapped的hEvent這個事件會觸發。這時Overlapped的InternalHigh表示接受的位元組數。Internal表示錯誤碼。訊息的內容即是你當初調用WSARecv時傳入的lpBuffers參數。
4.程式碼群組織
以服務端為例
首先傳入WSARecv的幾個參數必定與一個socket關聯。而且這些參數在非同步呼叫完成之後,但是以後還要用(在WaitForMutiObjects時要用到),而且每一個socket得擁有一個不同的Event來標識是哪個用戶端來訊息了。所以為每一個用戶端socket構造一個Overlapped結構。比如我測試的代碼中每一個用戶端都有這樣一個結構體,而且當accept來的時候表示有新的socket串連,就得產生這樣一個結構體,當用戶端掉線的時候,就得刪除這樣一個結構體
下面就是這個結構體:
struct CClientInfo{public: CClientInfo() { ZeroMemory(&m_ol,sizeof(m_ol)); ZeroMemory(m_szBuf,256); m_ol.hEvent = WSACreateEvent(); } ~CClientInfo() { WSACloseEvent(m_ol.hEvent); } WSAOVERLAPPED m_ol; SOCKET sSocket; CString strIp; u_short nPort; CString GetShowText(); char m_szBuf[256];};
下面是兩個函數,一個是當用戶端串連的時候,一個是當用戶端斷開的時候
CClientInfo * CServerDlg::OnSocketConnected(SOCKET sClientSocket,sockaddr_in * saClient){ u_short uPort = ntohs(((sockaddr_in *)saClient)->sin_port); CString strIp = CA2T(inet_ntoa(((sockaddr_in *)saClient)->sin_addr)); CClientInfo * pClientInfo = new CClientInfo; pClientInfo->nPort = uPort; pClientInfo->strIp = strIp; pClientInfo->sSocket = sClientSocket; LockClientArray(); m_ClientArray.Add(pClientInfo); int nIndexInserted = m_ClientListBox.AddString(pClientInfo->GetShowText()); m_ClientListBox.SetItemData(nIndexInserted,pClientInfo->sSocket); UnLockClientArray(); return pClientInfo;}void CServerDlg::OnSocketDisconnect(SOCKET aClientSocket){ LockClientArray(); for(int i = 0;i<m_ClientArray.GetCount();i++) { CClientInfo * pClientInfo = m_ClientArray.GetAt(i); if(pClientInfo->sSocket == aClientSocket) { m_ClientListBox.DeleteString(m_ClientListBox.FindString(0,pClientInfo->GetShowText())); delete pClientInfo; m_ClientArray.RemoveAt(i); break; } } UnLockClientArray();}5.沒有測試的內容和疑問
如果WSARecv調用兩次會是什麼情況,有沒有影響。
我沒有用非同步AcceptEx,感覺這個函數非同步了,作用也不大,以後如果需要的話,再學習吧
發送的時候沒有用WSASend,以後再學習
Socket重疊IO