多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > 互聯網 > 網絡編程(55)—— Windows下使用WSASocket基于Completion Routine進行IO重疊

網絡編程(55)—— Windows下使用WSASocket基于Completion Routine進行IO重疊

來源:程序員人生   發布時間:2017-03-07 08:23:49 閱讀次數:2697次

1、引言

        上1文中我們介紹了使用基于事件進行IO堆疊的方法,本文主要介紹另外1種,基于回調函數void CALLBACK CompletionRoutine(DWORD dwError,DWORDszRecvBytes,LPWSAOVERLAPPED lpOverlapped,DWORD flags)進行IO堆疊。首先,我們先介紹1種線程的狀態——alertable wait狀態。

        甚么是alertable wait狀態?

alertable wait狀態是線程等待接收操作系統消息的狀態,我們之前接觸過的WSAWaitForMultipleEvents函數就能夠觸發線程這類狀態。我們先來回顧下WSAWaitForMultipleEvents的函數原型:

DWORDWSAWaitForMultipleEvents(
  __in DWORD cEvents,
  __in const WSAEVENT *lphEvents,
  __in BOOL fWaitAll,
  __in DWORD dwTimeout,
  __in BOOL fAlertable
);

        它的第5個參數fAlertable就是設置alertablewait狀態的開關,當它設置為True時就會激活線程的alertable wait狀態。我們定義的回調函數CompletionRoutine,只有在線程進入alertablewait狀態后才會被操作系統調用。

2、定義CompletionRoutine回調函數

        我們先來回顧下WSARecv的原型(WSASend類似):

int WSARecv(
  __in     SOCKET s,
  __inout  LPWSABUF lpBuffers,
  __in     DWORD dwBufferCount,
  __out    LPDWORD lpNumberOfBytesRecvd,
  __inout  LPDWORD lpFlags,
  __in     LPWSAOVERLAPPED lpOverlapped,
  __in     LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

        在上1文中,采取基于事件的IO堆疊時,將WSARecv最后1個參數設置成了NULL。而實際上他就是我們定義的回調函數CompletionRoutine的函數指針。而CompletionRoutine函數的后3個參數分別來自WSARecv的第4~6個參數。當線程進入alertable wait狀態后,操作系統就會履行CompletionRoutine函數。

 

3、利用實例

        上述是使用CompletionRoutine的理論部份,下面我們通過實例對CompletionRoutine進行學習。使用CompletionRoutine進行數據接收的例子:

// WSASocketCompletionRoutineServ.cpp : 定?§義°?控?制?臺??§應®|用®?程¨?序¨°的ì?入¨?口¨2點ì?。?ê
//
 
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include <WinSock2.h>
#include <string.h>
 
#pragma comment(lib,"ws2_32.lib")
 
#define BUF_SIZE 30
 
void ErrorHandler(const char* message);
void CALLBACK CompletionRoutine(DWORD dwError,DWORDszRecvBytes,LPWSAOVERLAPPED lpOverlapped,DWORD flags);
 
char buf[BUF_SIZE];
DWORD recvBytes = 0;
WSABUF wsaBuf;
int _tmain(int argc, _TCHAR* argv[])
{
    SOCKETservSock,clntSock;
    SOCKADDR_INservAddr,clntAddr;
    int clntAddrSz;
   
    WSAOVERLAPPEDoverLapped;
    HANDLEhEvent;
   
    DWORDret,flags=0;
 
    WSADATAwsaData;
    WSAStartup(MAKEWORD(2,2),&wsaData);
 
 
 
    //創???建?§支?ì持?IO復??用®?的ì?套??á接¨®字á?
    servSock=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
    if(servSock==INVALID_SOCKET)
        ErrorHandler("WSASocket Error");
 
    memset(&servAddr,0,sizeof(servAddr));
    servAddr.sin_family=AF_INET;
    servAddr.sin_addr.s_addr=htonl(INADDR_ANY);
    servAddr.sin_port=htons(atoi("8888"));
 
    if(bind(servSock,(SOCKADDR*)&servAddr,sizeof(servAddr))==SOCKET_ERROR)
        ErrorHandler("bind error");
 
    if(listen(servSock,5)==SOCKET_ERROR)
        ErrorHandler("listen error");
 
    clntAddrSz=sizeof(clntAddr);
    clntSock=accept(servSock,(SOCKADDR*)&clntAddr,&clntAddrSz);
 
    memset(&overLapped,0,sizeof(overLapped));
    wsaBuf.buf=buf;
    wsaBuf.len=BUF_SIZE;
    hEvent=WSACreateEvent();
    overLapped.hEvent=hEvent;
 
    if(WSARecv(clntSock,&wsaBuf,1,&recvBytes,&flags,&overLapped,CompletionRoutine)==SOCKET_ERROR)
    {
        if(WSAGetLastError()==WSA_IO_PENDING)
            puts("background recieve data");
    }
    ret=WSAWaitForMultipleEvents(1,&hEvent,false,WSA_INFINITE,true);
    if(ret==WAIT_IO_COMPLETION)
        puts("Overlapped I/O Compeleted");
    else
        ErrorHandler("WSARecv Error");
 
    WSACloseEvent(hEvent);
    closesocket(servSock);
    closesocket(clntSock);
    WSACleanup();
    return 0;
}
 
void CALLBACK CompletionRoutine(DWORD dwError,DWORDszRecvBytes,LPWSAOVERLAPPED lpOverlapped,DWORD flags)
{
    if(dwError!=0)
    {
        ErrorHandler("CompletionRoutine Error");
    }
    else
    {
        recvBytes=szRecvBytes;
        printf("Recieve Message:%s\n",buf);
    }
}
 
void ErrorHandler(const char* message)
{
    fputs(message,stderr);
    fputc('/n',stderr);
    exit(1);
}

第79~90行,是對CompletionRoutine函數的定義,在函數中操作系統將實際接收的字節szRecvBytes等信息傳遞給我們,在函數里對收到的buf進行打印

第17~19行,分別聲明了用于接收數據的buf,實際接收的字節數recvBytes,和用于WSARecv調用的wsaBuf,由于在回調函數CompletionRoutine中也會用到這些變量,所以它們被聲明成了全局變量。

第55~59行,初始化進行IO堆疊的相干變量,包括wsaBuf、hEvent和overLapped。

第61行,調用WSARecv進行數據的接收,并將定義好的CompletionRoutine函數傳給其最后1個參數。

       下面是使用WSASend函數的1個例子,由于上上面的例子原理上相同,這里就不在贅述。

// WSASocketCompletionRoutineClnt.cpp : 定?§義°?控?制?臺??§應®|用®?程¨?序¨°的ì?入¨?口¨2點ì?。?ê
//
 
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include <WinSock2.h>
#include <string.h>
 
#pragma comment(lib,"ws2_32.lib")
 
#define BUF_SIZE 30
 
void ErrorHandler(const char* message);
void CALLBACK CompletionRoutine(DWORD dwError,DWORDszRecvBytes,LPWSAOVERLAPPED lpOverlapped,DWORD flags);
 
char buf[BUF_SIZE]="Hello world";
DWORD recvBytes = 0;
int _tmain(int argc, _TCHAR* argv[])
{
    SOCKETservSock;
    SOCKADDR_INservAddr;
 
    WSAOVERLAPPEDoverLapped;
    HANDLEhEvent;
    WSABUFwsaBuf;
    DWORDret,flags=0;
 
    WSADATAwsaData;
    WSAStartup(MAKEWORD(2,2),&wsaData);
 
 
 
    //創???建?§支?ì持?IO復??用®?的ì?套??á接¨®字á?
    servSock=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
    if(servSock==INVALID_SOCKET)
        ErrorHandler("WSASocket Error");
 
    memset(&servAddr,0,sizeof(servAddr));
    servAddr.sin_family=AF_INET;
    servAddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    servAddr.sin_port=htons(atoi("8888"));
 
    connect(servSock,(SOCKADDR*)&servAddr,sizeof(servAddr));
 
    memset(&overLapped,0,sizeof(overLapped));
    wsaBuf.buf=buf;
    wsaBuf.len=BUF_SIZE;
    hEvent=WSACreateEvent();
    overLapped.hEvent=hEvent;
 
    if(WSASend(servSock,&wsaBuf,1,&recvBytes,flags,&overLapped,CompletionRoutine)==SOCKET_ERROR)
    {
        if(GetLastError()==WSA_IO_PENDING)
            puts("background data send");
    }
    ret=WSAWaitForMultipleEvents(1,&hEvent,false,WSA_INFINITE,true);
    if(ret==WAIT_IO_COMPLETION)
        puts("Overlapped I/O Compeleted");
    else
        ErrorHandler("WSASend Error");
 
    WSACloseEvent(hEvent);
    closesocket(servSock);
    WSACleanup();
    return 0;
}
 
void CALLBACK CompletionRoutine(DWORD dwError,DWORDszRecvBytes,LPWSAOVERLAPPED lpOverlapped,DWORD flags)
{
    if(dwError!=0)
    {
        ErrorHandler("CompletionRoutine Error");
    }
    else
    {
        recvBytes=szRecvBytes;
        printf("Send Message:%s\n",buf);
    }
}
 
void ErrorHandler(const char* message)
{
    fputs(message,stderr);
    fputc('/n',stderr);
    exit(1);
}
 


Github位置:
https://github.com/HymanLiuTS/NetDevelopment
克隆本項目:
git clone git@github.com:HymanLiuTS/NetDevelopment.git
獲得本文源代碼:
git checkout NL55

 

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 国产精品无码久久综合网 | 欧美一级毛片欧美一级无片 | 欧美精品综合一区二区三区 | 五月婷婷免费视频 | 欧美另类bbwhd| 国产综合成人久久大片91 | 欧美日韩亚洲一区二区 | 日本性一级 | 中文字幕免费在线观看 | 国产欧美一区二区成人影院 | 国内精品久久久久影院不卡 | 性新婚a大黄毛片 | 亚洲精品福利一区二区 | 最近最新免费中文字幕8 | 综合网自拍| 美女网站在线观看 | 国产精品成久久久久三级 | www.yw尤物| 欧美一区二区三区东南亚 | 曰韩一级 | 亚洲一区日本 | 亚洲综合一区二区三区四区 | 青草超级碰碰在线视频 | 国99久9在线 | 免费 | 一级做a爱过程免费视频超级 | 2020久久精品亚洲热综合一本 | 视频二区 调教中字 知名国产 | 伊人蕉久| 性欧美孕妇xxxx | 波多野野结衣1区二区 | 黄色wwwcom | 亚洲国产第一 | 一级毛片区 | 情侣偷偷看的羞羞视频网站 | 日本一区二区三区免费高清在线 | 中文字幕在线视频免费观看 | 国内精品伊人久久久久 | 国产精品无码久久av | 欧美另类69xxxxx极品 | 国产综合视频在线观看 | 国产精品1区 |