windows 網路編程筆記 winsocket API CSocket CAsyncSocket__編程

來源:互聯網
上載者:User

MFC對SOCKET編程的支援其實是很充分的,然而其文檔是語焉不詳的。以至於大多數用VC編寫的功能稍
複雜的網路程式,還是使用API的。故CAsyncSocket及CSocket事實上成為疑難,群眾多敬而遠之。餘
好事者也,不忍資源浪費,特為之註解。網友關於阻塞、非阻塞等的說法不是很可信。

====================================================

1.  MSDN winsocket API 函數說明:int WSAAsyncSelect(
  __in          SOCKET s,
  __in          HWND hWnd,
  __in          unsigned int wMsg,
  __in          long lEvent
);

The WSAAsyncSelect function is used to request that WS2_32.DLL should send a message to the window hWnd when it detects any network event specified by the lEvent parameter. The message that should be sent is specified by the wMsg parameter. The socket for which notification is required is identified by the s parameter.


The WSAAsyncSelect function automatically sets socket s to nonblocking mode, regardless of the value of lEvent. To set socket s back to blocking mode, it is first necessary to clear the event record associated with socket s via a call to WSAAsyncSelect with lEvent set to zero. You can then call ioctlsocket or WSAIoctl to set the socket back to blocking mode. For more information about how to set the nonblocking socket back to blocking mode, see the ioctlsocket and WSAIoctl functions.

=========================================================

2. windows 網路編程摘錄:第七章 WINSOCKET I/O 方法:

就像我們前面提到的那樣, Wi n d o w s通訊端在兩種模式下執行I / O操作:鎖定和非鎖定。 在鎖定模式下,在I / O操作完成前,執行操作的Wi n s o c k函數(比如s e n d和r e c v)會一直等候下去,不會立即返回程式(將控制權交還給程式)。而在非鎖定模式下, Wi n s o ck函數無論如何都會立即返回。所以我們必須採取一些適當的步驟,讓鎖定和非鎖定通訊端能夠滿足各種場合的要求。
若應用程式針對一個通訊端調用了W S A A s y n c S e l e c t,那麼通訊端的模式會從“鎖定”自動變

成“非鎖定”,我們在前面已提到過這一點。這樣一來,假如調用了像W S A R e c v這樣的Wi n s o c kI / O函數,但當時卻並沒有資料可用,那麼必然會造成調用的失敗,並返回W S A E W O U L D B L O C K錯誤。為防止這一點,應用程式應依賴於由W S A A s y n c S e l e c t的u M s g參數指定的使用者自訂視窗訊息,來判斷網路事件類型何時在通訊端上發生;而不應盲目地進行調用。

===================================================

3. 關於 CSocket、CAsyncSocket  MFC源碼  摘錄:

分析代碼以及實際測試得知,CSocket 預設是非塞調用的,而CSocket::accept函數是阻塞的

代碼位於 afxsock.h sockcore.cpp afxsock.inl 等檔案

 CSocket::CSocket(){m_pbBlocking = NULL;m_nConnectError = -1;m_nTimeOut = 2000;}AFXSOCK_INLINE BOOL CSocket::Create(UINT nSocketPort, int nSocketType, LPCTSTR lpszSocketAddress){ return CAsyncSocket::Create(nSocketPort, nSocketType, FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE, lpszSocketAddress); }BOOL CAsyncSocket::Create(UINT nSocketPort, int nSocketType,long lEvent, LPCTSTR lpszSocketAddress){if (Socket(nSocketType, lEvent)){if (Bind(nSocketPort,lpszSocketAddress))return TRUE;int nResult = GetLastError();Close();WSASetLastError(nResult);}return FALSE;}BOOL CAsyncSocket::Socket(int nSocketType, long lEvent,int nProtocolType, int nAddressFormat){ASSERT(m_hSocket == INVALID_SOCKET);m_hSocket = socket(nAddressFormat,nSocketType,nProtocolType);if (m_hSocket != INVALID_SOCKET){CAsyncSocket::AttachHandle(m_hSocket, this, FALSE);return AsyncSelect(lEvent);}return FALSE;}BOOL CAsyncSocket::AsyncSelect(long lEvent){ASSERT(m_hSocket != INVALID_SOCKET);_AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;ASSERT(pState->m_hSocketWindow != NULL);     
//  WSAAsyncSelect
return WSAAsyncSelect(m_hSocket, pState->m_hSocketWindow,WM_SOCKET_NOTIFY, lEvent) != SOCKET_ERROR;

}

3.測試代碼  CSocket 收發檔案:

  1.傳送檔案

void CSendFileDlg::OnButtonSendfile(){    // TODO: Add your control notification handler code here    CSocket sockTemp;    sockTemp.Create(7803); //連接埠為7803,任意的    AfxMessageBox("開始調用 Listen");    sockTemp.Listen(1);//只接受一個串連    AfxMessageBox("Listen函數返回");        CSocket  sockSend;            AfxMessageBox("開始調用用 Accept)");//經測試,CSocket::Accept是阻塞函數    sockTemp.Accept(sockSend);//注意,sockTemp已交了自己的指標地址到sockSend,故不用Close    AfxMessageBox(" Accept返回)");    CFile file;    if( !file.Open("D:\\movie.mkv", CFile::modeRead) )    {        AfxMessageBox("開啟D:\\Test檔案出錯。");        sockSend.Close();        return;    }    int  nBufSize = 1024 * 5;   //預設為拔號,5K。當為ADSL時,可將此值改大為約等於下載K數,如300K    int  nSize = nBufSize;    LPBYTE  pBuf = new BYTE[nBufSize];        DWORD dwTemp = 0;    BOOL bTest = sockSend.AsyncSelect(0);//由於CSocket實際是非同步,將它變為同步(阻塞)方式。    sockSend.IOCtl( FIONBIO, &dwTemp);//用IOCtl要將AsyncSelect的第一個參數為0,參看MSDN    UINT uLength = file.GetLength();    sockSend.Send(&uLength, 4);//傳送檔案大小到接收方(Client端)        int nNumByte;    UINT uTotal = 0;    while(uTotal < uLength)    {        if(uLength - uTotal < nBufSize)            nSize = uLength - uTotal;//當小於緩衝區nTEST時的處理        file.Read(pBuf , nSize);        nNumByte = sockSend.Send(pBuf, nSize);//注意nNumByte為實際的發送位元組數,不要以nSize為準        if(nNumByte == SOCKET_ERROR)        {            AfxMessageBox("發送錯誤。");            goto LabelExit;        }        uTotal += nNumByte;    }    AfxMessageBox("傳送檔案成功。");LabelExit:    delete[] pBuf;    file.Close();    sockSend.Close();}

3.2接收檔案:

void CRecvFileDlg::OnButtonRecvfile() {// TODO: Add your control notification handler code hereCFile file;file.Open("C:\\copymovie.mkv", CFile::modeCreate | CFile::modeWrite);CSocket  sockRecv;sockRecv.Create();if(!sockRecv.Connect("127.0.0.1", 7803))//接收方地址,若上網,可改為實際IP地址,連接埠要跟Server端相同。{                                       //Connect函數馬上返回,不會阻塞AfxMessageBox("連結失敗");return;}DWORD dwTemp =  0;sockRecv.AsyncSelect(0);sockRecv.IOCtl( FIONBIO, &dwTemp);//變為阻塞方式UINT uLength;sockRecv.Receive(&uLength, 4);//接收發方(Server端)的檔案大小int  nBufSize = 1024  * 5;//用預設的拔號上網下載速度為準 5K,如果用ADSL,可改為300K,或按你實際的IE DownLoad值int  nSize = nBufSize;LPBYTE  pBuf = new BYTE[nBufSize];int  nNumByte;UINT uTotal = 0;while(uTotal < uLength){if(uLength - uTotal < nBufSize)nSize = uLength - uTotal;nNumByte = sockRecv.Receive(pBuf, nSize);if(nNumByte == SOCKET_ERROR){AfxMessageBox("接收錯誤。");goto LabelExit;}file.Write(pBuf, nNumByte);uTotal += nNumByte;//以實際接收位元組為準}AfxMessageBox("接收檔案成功。");LabelExit:delete[] pBuf;file.Close();sockRecv.Close();}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.