端口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);
}
}