标题:端口I/O模型原理的网络通信
取消只看楼主
fwherr
Rank: 1
等 级:新手上路
帖 子:30
专家分:0
注 册:2014-6-8
结帖率:50%
 问题点数:0 回复次数:0 
端口I/O模型原理的网络通信
想请朋友帮忙在网络通信多线实现过程如下代码怎样理解,或者调用过程,对这代码很不明白,请帮解释,谢谢!

enum IOType
{
    OP_IORead,
    OP_IOWrite,
};

typedef struct tagUserList { //define userlist list item structure
    char szUsername[MAX_NAME_SIZE];
    char szIP[20];            //user ip
    char sztime[10];        //login time
    struct tagUserList *next;
}ULNode;

//struct define
typedef struct _BUFFER_OBJ
{
    char  DataBuffer[DEFAULT_BUFFER_SIZE];           // Buffer for recv/send
    LONG  sendcount;
} BUFFER_OBJ;

typedef struct _CLIENT_OBJ
{
    WSAOVERLAPPED        ol;
    char                 clientname[MAX_NAME_SIZE];        //client login name
    char                 time[10];                    //login time
    SOCKET                 sclient;
    WSABUF                 RecvDataBuf;
    WSABUF                 SendDataBuf;
    IOType                 optype;
    BOOL                 broadcast;
    SOCKADDR_IN             addressinfo;
    BUFFER_OBJ           *recvbuf;
    BUFFER_OBJ             *sendbuf;
    BOOL                 firstrecv;                    //first recv data,it is login name
    CRITICAL_SECTION     SockCritSec;    // Protect access to this structure
    struct _CLIENT_OBJ  *next;
} CLIENT_OBJ;

DWORD WINAPI ChatServer::ServerWorkerThread(LPVOID CompletionPortID)
{
   HANDLE CompletionPort = (HANDLE) CompletionPortID;
   DWORD BytesTransferred;
   CLIENT_OBJ* clientobj;
   DWORD    SendBytes, RecvBytes;
   DWORD    Flags;
   BOOL        hasnamed = FALSE;
   int      rc;
   char        errormsg[30];

   while(TRUE)
   {        
      if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,//工作线程与完成端品
         (LPDWORD)&clientobj,(LPOVERLAPPED*)&clientobj, INFINITE) == 0)
      {
          rc = GetLastError();
          if(rc != ERROR_NETNAME_DELETED)
          {
              wsprintf(errormsg,"GetQueuedCompletionStatus failed with error %d", rc);
              ::MessageBox(NULL,errormsg,"Error",MB_OK);
              return -1;
          }
      }

      EnterCriticalSection(&clientobj->SockCritSec);

      switch(clientobj->optype)
      {
      case OP_IORead:

          if (BytesTransferred == 0)        //客户退出聊天室
            {
                char name[MAX_NAME_SIZE],leavemsg[50];
                BOOL renamed = FALSE;
                strcpy(name,clientobj->clientname);
                if (closesocket(clientobj->sclient) == SOCKET_ERROR)
                {
                    wsprintf(errormsg,"closesocket() failed with error %d", WSAGetLastError());
                    ::MessageBox(NULL,errormsg,"Error",MB_OK);
                    return -1;
                }
                clientobj->sclient = INVALID_SOCKET;
                renamed = clientobj->firstrecv;
                g_pchatserver->FreeClientObj(clientobj);
                if(!renamed)                //如果有重复名称错误,系统将不广播退出消息
                {
                    BUFFER_OBJ *newobj = (BUFFER_OBJ *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BUFFER_OBJ));
                    if (newobj == NULL)
                    {
                        wsprintf(errormsg, "PublicSendBufffer: HeapAlloc failed: %d", GetLastError());
                        ::MessageBox(NULL,errormsg,"Error",MB_OK);
                        return -1;
                    }
                    wsprintf(newobj->DataBuffer,"[系统消息]%s离开聊天室。\r\n",name);
                    g_pchatserver->SendPublicMessage(newobj);
                    wsprintf(leavemsg,"*********[客户%s退出聊天室]*********\r\n",name);
                    g_smsg = leavemsg;
                    ::PostMessage(g_pchatserver->m_showmsgdlg,WM_UPDATEMSG,NULL,NULL);
                    continue;
                }
          }
        else            //广播聊天消息或客户端登录信息
        {            
            clientobj->broadcast = TRUE;
            if(clientobj->firstrecv)
            {   
                strncpy(clientobj->clientname,clientobj->RecvDataBuf.buf,BytesTransferred);
                WaitForSingleObject(g_hClientInfoMutex,INFINITE);
                g_pchatserver->m_clientcount++;
                if(g_puserlist)
                {
                    ULNode* ulptr = g_puserlist;
                    while(ulptr)
                    {
                        if(!strcmp(ulptr->szUsername,clientobj->clientname))
                        {//如果有重复的名称,关闭套接字和等待客户端退出
                            hasnamed = TRUE;
                            clientobj->optype = OP_IORead;
                            ZeroMemory(&(clientobj->ol), sizeof(OVERLAPPED));
                            clientobj->RecvDataBuf.len = DEFAULT_BUFFER_SIZE;
                            clientobj->RecvDataBuf.buf = clientobj->recvbuf->DataBuffer;
                            Flags = 0;
                            if (WSARecv(clientobj->sclient, &(clientobj->RecvDataBuf), 1, &RecvBytes, &Flags,
                            &(clientobj->ol), NULL) == SOCKET_ERROR)
                            {
                                if (WSAGetLastError() != ERROR_IO_PENDING)
                                {
                                    wsprintf(errormsg,"WSARecv() failed with error %d", WSAGetLastError());
                                    ::MessageBox(NULL,errormsg,"Error",MB_OK);
                                    return -1;
                                }
                            }
                            shutdown(clientobj->sclient,SD_SEND);
                            break;
                        }
                        ulptr = ulptr->next;
                    }
                }
                ReleaseMutex(g_hClientInfoMutex);
                if(hasnamed)
                {
                    hasnamed = FALSE;
                    continue;
                }
                else
                {
                    SYSTEMTIME  time;
                    char    welmsg[50];
                    GetSystemTime(&time);
                    wsprintf(clientobj->time,"%d:%d:%d",time.wHour+8,time.wMinute,time.wSecond);
                    wsprintf(welmsg,"[系统消息]欢迎%s进入...\r\n",clientobj->clientname);
                    strcpy(clientobj->recvbuf->DataBuffer,welmsg);
                    g_pchatserver->UpdateUserList(clientobj);
                    wsprintf(welmsg,"*********[客户%s进入聊天室]*********\r\n",clientobj->clientname);
                    g_smsg = welmsg;
                    ::SendMessage(g_pchatserver->m_showmsgdlg,WM_UPDATEMSG,NULL,NULL);
                    clientobj->firstrecv = FALSE;
                }
            }
            else
            {
                g_smsg += '[';
                g_smsg += clientobj->clientname;
                g_smsg += "]:";
                g_smsg += clientobj->recvbuf->DataBuffer;
                g_smsg += "\r\n";
                ::SendMessage(g_pchatserver->m_showmsgdlg,WM_UPDATEMSG,NULL,NULL);
                char tmp[DEFAULT_BUFFER_SIZE];
                wsprintf(tmp,"[%s]:%s",clientobj->clientname,clientobj->recvbuf->DataBuffer);
                strcpy(clientobj->recvbuf->DataBuffer,tmp);
            }
            clientobj->sendbuf = clientobj->recvbuf;            //先取接收缓冲区发送缓冲区
            clientobj->recvbuf = g_pchatserver->GetBufferObj(); //get new receive buffer
            
            WaitForSingleObject(g_pchatserver->m_hlinkmutex,INFINITE);    //wait for finishing
            CLIENT_OBJ *ptr = g_pchatserver->m_Client;
            clientobj->sendbuf->sendcount = g_pchatserver->m_clientcount;
            while(ptr)        //通过所有客户端发送广播
            {
                    ptr->optype = OP_IOWrite;
                    ZeroMemory(&(ptr->ol), sizeof(OVERLAPPED));
                    ptr->SendDataBuf.buf = clientobj->sendbuf->DataBuffer;
                    ptr->SendDataBuf.len = DEFAULT_BUFFER_SIZE;
                    ptr->sendbuf = clientobj->sendbuf;
                    if (WSASend(ptr->sclient, &(ptr->SendDataBuf), 1, &SendBytes, 0,
                    &(ptr->ol), NULL) == SOCKET_ERROR)
                    {
                        if (WSAGetLastError() != ERROR_IO_PENDING)
                        {
                            wsprintf(errormsg,"WSASend() failed with error %d", WSAGetLastError());
                            ::MessageBox(NULL,errormsg,"Error",MB_OK);
                            return -1;
                        }
                    }
            
                    ptr = ptr->next;
            }
            ReleaseMutex(g_pchatserver->m_hlinkmutex);
        }
        break;
      case OP_IOWrite:
            clientobj->optype = OP_IORead;
            if(clientobj->sendbuf->sendcount != 0) clientobj->sendbuf->sendcount--;
            if(clientobj->sendbuf->sendcount ==0)
            {//Send Message Complete Successfully
            //    ::MessageBox(NULL,"Test","Debug",MB_OK);
                g_pchatserver->FreeBufferObj(clientobj->sendbuf);
                clientobj->sendbuf = NULL;
            }
            if(clientobj->broadcast)    //if it's the message sender, then start receive new message
            {
                ZeroMemory(&(clientobj->ol), sizeof(OVERLAPPED));
                clientobj->RecvDataBuf.len = DEFAULT_BUFFER_SIZE;
                clientobj->RecvDataBuf.buf = clientobj->recvbuf->DataBuffer;
                Flags = 0;
                if (WSARecv(clientobj->sclient, &(clientobj->RecvDataBuf), 1, &RecvBytes, &Flags,
                &(clientobj->ol), NULL) == SOCKET_ERROR)
                {
                    if (WSAGetLastError() != ERROR_IO_PENDING)
                    {
                        wsprintf(errormsg,"WSARecv() failed with error %d", WSAGetLastError());
                        ::MessageBox(NULL,errormsg,"Error",MB_OK);
                        return -1;
                    }
                }
                clientobj->broadcast = FALSE;
            }
        break;
      }
      LeaveCriticalSection(&clientobj->SockCritSec);
    }
}
搜索更多相关主题的帖子: 朋友 structure 模型 通信 网络 
2015-07-27 17:40



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-455833-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.051637 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved