zoukankan      html  css  js  c++  java
  • socket-重叠模型(overlap)

    socket-重叠模型(overlap)
    重叠模型的基本设计原理便是让应用程序使用一个重叠的数据结构,一次投递一个或多个Winsock I/O请求。针对那些提交的请求,在它们完成之后,应用程序可为它们提供服务。该模型适用于除Windows CE之外的各种Windows平台。模型的总体设计以Win32重叠I/O机制为基础。那个机制可以通过ReadFile和WriteFile两个函数,针对设备执行I/O操作。

    关键是理解“重叠”两个字,就是你把发送的数据交给系统,然后自己做别的事情,在你干自己的事情时,系统同时也正在完成你交给他的任务,两者同时进行。系统完成后会调用你给他的代码或者通知你。所以,“重叠”指的是时间上的重叠。

    要想在一个套结字上使用重叠I/O模型,首先必须使用WSA_FLAG_OVERLAPPED这个标志,创建一个套结字。如下所示:
    s = WSASocket( AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED );
    创建套结字时,假如使用的是socket函数,而非WSASocket函数,那么会默认设置WSA_FLAG_OVERLAPPED标志。该标志可与下面函数相关联:

    WSASend
    WSASendTo
    WSARecv
    WSARecvFrom
    WSAIoctl
    AcceptEx
    TransmitFile

    若随一个WSAOVERLAPPED结构一起调用这些函数,函数会立即完成并返回,无论套结字是否设置为阻塞模式。主要有两个方法用来管理一个重叠I/O请求的完成:我们的应用程序客等待“事件对象通知”,亦可通过“完成例程”,对已完成的请求加以处理。

    编写一个简单重叠I/O模式服务器程序,基本步骤如下:
    1)创建一个套结字,开始在指定的端口上监听连接请求。
    2)接受一个进入的连接请求。
    3)为接受的套结字新建一个WSAOVERLAPPED结构,并为该结构分配一个事件对象句柄。也将事件对象句柄分配给一个事件数组,以便稍后WSAWaitForMultipleEvents函数使用。
    4)在套结字上投递一个异步WSARecv请求,指定参数为WSAOVERLAPPED结构。(函数通常会以失败告终,返回SOCKET_ERROR错误状态WSA_IO_PENDING)。
    5)使用步骤3)的事件数组,调用WSAWaitForMultipleEvents函数,并等待与重叠调用关联在一起的事件进入“已传信”状态(等待那个事件触发)。
    6)WSAWaitForMultipleEvents函数完成后,针对事件数组,调用WSAResetEvent(重设事件)函数,从而重设事件对象,并对完成的重叠请求进行处理。
    7)使用WSAGetOverlappedResult函数,判断重叠调用的返回状态是什么。
    8)在套结字上投递另一个重叠WSARecv请求。
    9)重复步骤5)~8)。

    下面附上源代码

    Server端代码:

    #include <stdio.h>
    #include <Winsock2.h>
    #pragma comment(lib, "WS2_32.lib")

    #define MYPORT 8001
    #define MYIP "127.0.0.1"
    #define DATA_BUFSIZE 1024

    void showerror(const char* function);
    void main()
    {
    WORD wVersion = MAKEWORD( 2, 0 );
    WSADATA wsdata;
    WSABUF DataBuf;
    DWORD EventTotal = 0;
    DWORD RecvBytes = 0;
    DWORD BytesTransferred = 0;
    DWORD Flags = 0;
    DWORD Index = 0;
    WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
    WSAOVERLAPPED AcceptOverlapped;
    SOCKET ListenSocket, AcceptSocket;
    struct sockaddr_in addr;
    int addrlen = sizeof(struct sockaddr);
    char szbuffer[DATA_BUFSIZE];

    // 加载socket2.0 dll
    int nResult = WSAStartup( wVersion, &wsdata );
    if( nResult != 0 )
    {
    printf( "error in function WSAStartup(): %d ", WSAGetLastError() );
    return;
    }
    printf("WSAStartup success ");


    // Step 1:
    // Start Winsock and set up a listening socket
    printf("create socket... ");
    ListenSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
    if( ListenSocket == INVALID_SOCKET )
    {
    showerror( "socket" );
    return;
    }
    printf("create socket success ");

    addr.sin_family = AF_INET;
    addr.sin_port = htons( MYPORT );
    addr.sin_addr.s_addr = inet_addr( MYIP );
    printf("bind socket... ");
    nResult = bind( ListenSocket, (struct sockaddr*)&addr, sizeof(struct sockaddr_in) );
    if( nResult == SOCKET_ERROR )
    {
    showerror( "bind" );
    return;
    }
    printf("bind socket success ");

    printf("listen socket... ");
    nResult = listen( ListenSocket, 5 );
    if( nResult == SOCKET_ERROR )
    {
    showerror( "listen" );
    return;
    }
    printf("listen socket success ");

    // Step 2:
    // Accept an inbound connection
    AcceptSocket = accept( ListenSocket, NULL, NULL );

    // Step 3:
    // Set up an overlapped structure
    EventArray[EventTotal] = WSACreateEvent();
    ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));
    AcceptOverlapped.hEvent = EventArray[EventTotal];

    DataBuf.len = DATA_BUFSIZE;
    DataBuf.buf = szbuffer;

    EventTotal++;

    // Step 4:
    // Post a WSARecv request to begin receiving data on the socket
    WSARecv( AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, NULL );

    while(TRUE)
    {
    // Step 5:
    // Wait for the overlapped I/O call to complete
    Index = WSAWaitForMultipleEvents( EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE );

    // Step 6:
    // Reset the signaled event
    WSAResetEvent( EventArray[Index - WSA_WAIT_EVENT_0] );

    // Step 7:
    // Determine the status of the overlapped
    WSAGetOverlappedResult( AcceptSocket, &AcceptOverlapped, &BytesTransferred, FALSE, &Flags );

    // First check to see whether the peer has closed the connection,
    // and if so, close the socket
    if( BytesTransferred == 0 )
    {
    showerror( "Closing socket" );
    closesocket( AcceptSocket );
    WSACloseEvent( EventArray[Index - WSA_WAIT_EVENT_0] );
    return;
    }

    // Do someting with the received data
    // DataBuf contains the received data
    printf( "Received: %s ", DataBuf.buf );

    // Step 8:
    // Post another WSARecv() request on the socket
    Flags = 0;
    ZeroMemory( &AcceptOverlapped, sizeof(AcceptOverlapped) );
    AcceptOverlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];

    DataBuf.len = DATA_BUFSIZE;
    DataBuf.buf = szbuffer;

    WSARecv( AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, NULL );
    }

    // 关闭socket
    closesocket( ListenSocket );

    // 卸载socket2.0 dll
    WSACleanup();
    }

    void showerror(const char* function)
    {
    LPVOID lpMsgBuf;

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,0, GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //默认语言
    (LPTSTR)&lpMsgBuf, 0, NULL );

    printf("error in function %s: 描述: %s ", function, (char*)lpMsgBuf);

    //释放内存
    LocalFree( lpMsgBuf );
    }

     
  • 相关阅读:
    (23)odoo中的domain表达式
    (11)lambda表达式用法
    (22)odoo 安装旧模块报错处理
    (21)odoo中的QWeb模板引擎
    (10)列表操作
    (09)异常处理
    (08)文件与目录
    (07)内存使用和变量赋值
    (06)正则表达式
    vue router路由(三)
  • 原文地址:https://www.cnblogs.com/S-volcano/p/5032087.html
Copyright © 2011-2022 走看看