欢迎光临
我们一直在努力

服务器开发入门——理解异步I/O

#include <stdio.h>
#include 
<Winsock2.h>
#include 
<windows.h>
#include 
<process.h>

#define DATA_BUFSIZE 4096

typedef struct
{
    WSAOVERLAPPED  overlap;
    WSABUF         DataBuf;
    
char           buffer[DATA_BUFSIZE];
    DWORD          NumberOfBytesRecvd;
    DWORD          Flags;
}PER_IO_OPERATION_DATA, 
*LPPER_IO_OPERATION_DATA;

void err_sys(
    
char* err
)
{
    fprintf(stderr, err);
    WSACleanup();
    exit(
-1);
}

unsigned __stdcall WorkThread(
    void* param
);

int main(int argc, char* argv[])
{
    HANDLE        CompletionPort;
    WSADATA        WsaData;
    
int            clilen = sizeof(sockaddr_in);
    sockaddr_in seraddr,cliaddr;
    SOCKET        listenfd, connfd;
    
int            opt = 1;

    SYSTEM_INFO systeminfo;
    unsigned    i;

    int            ret;
    LPPER_IO_OPERATION_DATA lpperiodata 
= NULL;

    HANDLE        hWorkThread;
    unsigned    threadID;

    if (WSAStartup (0x0101&WsaData) == SOCKET_error)
        err_sys(
"WSAStartup Failed\n");
    
    CompletionPort 
= CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 00);
    
if(CompletionPort == NULL)
        err_sys(
"create port error!\n");
    
    seraddr.sin_family 
= AF_INET;
    seraddr.sin_addr.s_addr 
= INADDR_ANY;
    seraddr.sin_port 
= htons(9877);

    listenfd = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
    
if(listenfd == INVALID_SOCKET)
        err_sys(
"socket error!\n");

    if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0)
        err_sys(
"setsockopt error!\n");

    if(bind(listenfd, (SOCKADDR*&seraddr, sizeof(seraddr)) == SOCKET_ERROR)
        err_sys(
"bind error\n");

    if(listen(listenfd, 5== SOCKET_ERROR)
        err_sys(
"listen error!\n");

    printf("server is listening...\n");

    if(CreateIoCompletionPort((HANDLE)listenfd, CompletionPort, (DWORD)listenfd, 0== NULL)
        err_sys(
"associate lisenfd error!\n");

    GetSystemInfo(&systeminfo);
    
    
//创建工作线程
    for (i = 0; i < systeminfo.dwNumberOfProcessors; i++)
    {
        hWorkThread 
= (HANDLE)_beginthreadex(NULL, 0&WorkThread, CompletionPort, 0&threadID);
        CloseHandle(hWorkThread);
    }

    for (;;)
    {    
        
if((connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen)) == SOCKET_ERROR )
        {
            
int code = WSAGetLastError();
            printf(
"accept error!\n");
            
continue;
        }
        
        
//将连接句柄关联到I/O完成端口
        if(CreateIoCompletionPort((HANDLE)connfd, CompletionPort, (DWORD)connfd, 0== NULL)
        {
            printf(
"associate connfd error!\n");
            closesocket(connfd);
            
continue;
        }
        
        lpPerIOData 
= (LPPER_IO_OPERATION_DATA)malloc(sizeof(PER_IO_OPERATION_DATA));
        ZeroMemory(lpPerIOData, 
sizeof(PER_IO_OPERATION_DATA));
        lpPerIOData
->DataBuf.len= DATA_BUFSIZE;
        lpPerIOData
->DataBuf.buf = lpPerIOData->buffer;
        ret 
= WSARecv(connfd, &lpPerIOData->DataBuf, 1&lpPerIOData->NumberOfBytesRecvd, \
                    
&lpPerIOData->Flags, &lpPerIOData->overlap, NULL);
        
if (ret == SOCKET_ERROR)
        {
            ret 
= WSAGetLastError();
            
if(ret != WSA_IO_PENDING)
            {
                printf(
"WSARecv error!\n");
                closesocket(connfd);
            }
        }
        
    }
    
    free(lpPerIOData);
    CloseHandle(CompletionPort);
    closesocket(listenfd);
    WSACleanup();
    
return 0;
}

//工作线程
unsigned __stdcall WorkThread( void* param)
{
    
int            ret;
    DWORD        BytesTransferred;
    SOCKET        connfd;

    LPPER_IO_OPERATION_DATA lpPerIOData = NULL;

    HANDLE        cport = (HANDLE) param;

    printf( "In work thread...\n" );
    
for(;;)
    {
        
//等待I/O完成通知
        ret = GetQueuedCompletionStatus(cport, &BytesTransferred, (LPDWORD)&connfd,\
                                        (LPOVERLAPPED 
*)&lpPerIOData, INFINITE);
        
if (ret == 0 || BytesTransferred == 0)
        {
            
//close connection
            closesocket(connfd);
        }
        
else
        {
            printf(
"recv %d bytes!\n", BytesTransferred);
            ret 
= send(connfd, lpPerIOData->buffer, BytesTransferred, 0);
            
if (ret == SOCKET_ERROR)
            {
                printf(
"send error!\n");
                closesocket(connfd);
                
continue;
            }
            
else
                printf(
"send %d bytes!\n", ret);
            
            ZeroMemory(
&lpPerIOData->overlap, sizeof(OVERLAPPED));
            ret 
= WSARecv(connfd, &lpPerIOData->DataBuf, 1&lpPerIOData->NumberOfBytesRecvd,\
                            
&lpPerIOData->Flags, &lpPerIOData->overlap, NULL);
            
if (ret == SOCKET_ERROR)
            {
                ret 
= WSAGetLastError();
                
if(ret != WSA_IO_PENDING)
                {
                    printf(
"WSARecv error!\n");
                    closesocket(connfd);
                }
            }
        }
    }
    _endthreadex( 
0 );
    
return 0;
}

  • 海报
海报图正在生成中...
赞(0) 打赏
声明:
1、本博客不从事任何主机及服务器租赁业务,不参与任何交易,也绝非中介。博客内容仅记录博主个人感兴趣的服务器测评结果及一些服务器相关的优惠活动,信息均摘自网络或来自服务商主动提供;所以对本博客提及的内容不作直接、间接、法定、约定的保证,博客内容也不具备任何参考价值及引导作用,访问者需自行甄别。
2、访问本博客请务必遵守有关互联网的相关法律、规定与规则;不能利用本博客所提及的内容从事任何违法、违规操作;否则造成的一切后果由访问者自行承担。
3、未成年人及不能独立承担法律责任的个人及群体请勿访问本博客。
4、一旦您访问本博客,即表示您已经知晓并接受了以上声明通告。
文章名称:《服务器开发入门——理解异步I/O》
文章链接:https://www.456zj.com/5554.html
本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址