当有客户端连接上来,并发送数据时,服务端一直在提示重叠IO操作进行中
请高手加我QQ 24645955 指点,并结分服务端代码如下
#include "stdafx.h"
#include "winsock2.h"
#pragma comment(lib,"ws2_32.lib")
#include "proto.h"
#include "iostream.h"
#include "server.h"定义结构体如下
struct stLoginMessage
{
char userName[10];
char password[10];
};//Client 注销时发送消息
struct stLogoutMessage
{
char userName[10];
};struct stUserListNode
{
char userName[10];
unsigned int ip;
unsigned int port;
};//Server Send to Client
struct stServerToClient
{
int iMessageType;
union _message
{
stUserListNode user;
}message;
};//Client 向Server发送消息格式
struct stMessage
{
int iMessageType;
union _message
{
stLoginMessage loginmember;
stLogoutMessage logoutmember;
}message;
};
//IO completion struct
typedef struct{
OVERLAPPED ol;
WSABUF dataBuf;
char buffer[BUFF_SIZE];
DWORD bytesSend;
DWORD bytesRecv;
stMessage stClientToServer;
}PER_IO_OPERATION_DATA,*LP_PER_IO_OPERATION_DATA;
typedef struct
{
SOCKET socket;
}PER_HANDLE_DATA,*LP_PER_HANDLE_DATA;
                
void InitSocket()
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2,2);
int error_flag;
error_flag = WSAStartup(wVersionRequested,&wsaData);
if(error_flag != 0)
{
printf("start error");
}

if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wHighVersion != 2))
{
printf("no useble dll");
WSACleanup();//
}
}
SOCKET MakeSocket()
{
SOCKET s;
s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(s < 0)
{
printf("create socket error");
}

return s;}
int main(int argc, char* argv[])
{

InitSocket(); SOCKET listener;
SOCKADDR_IN salocal;
listener = MakeSocket();
salocal.sin_family = AF_INET;
salocal.sin_port = htons(SERVER_PORT);
salocal.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(listener,(sockaddr *)&salocal,sizeof(sockaddr)) == 0)
{
printf("bind ok");
}
else
{
printf("bind error %d",WSAGetLastError());
} if(listen(listener,300) == 0)
{
printf("listen ok");
}
else
{
printf("listen error %d",WSAGetLastError());
} HANDLE hCompPort;
hCompPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);

/*
开启工作线程过数
*/

CreateWorkThread(hCompPort); LP_PER_HANDLE_DATA perHandleData;
LP_PER_IO_OPERATION_DATA perIoOperationData; SOCKET sClient;
   
while(true)
{
//绑定完成端口

sClient = WSAAccept(listener,NULL,NULL,NULL,0);
printf("socket connect %d",sClient);

if(sClient > 0)
{
printf("wsaaccept OK");
}
else
{
printf("wsaaccept error %d",WSAGetLastError());
}

perHandleData = (LP_PER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA));
perHandleData->socket = sClient;
CreateIoCompletionPort((HANDLE)sClient,hCompPort,(DWORD)perHandleData,0); //投递一次操作


//填充OVERLAPPED结构
perIoOperationData = (LP_PER_IO_OPERATION_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_OPERATION_DATA)); ZeroMemory(&(perIoOperationData->ol),sizeof(OVERLAPPED));

perIoOperationData->bytesSend = 0;
    perIoOperationData->bytesRecv = 0;
perIoOperationData->dataBuf.len = BUFF_SIZE;
perIoOperationData->dataBuf.buf = perIoOperationData->buffer;

DWORD flags = 0;


if( 0 == WSARecv(sClient,&(perIoOperationData->dataBuf),1,&(perIoOperationData->bytesRecv),&flags,(LPWSAOVERLAPPED)perIoOperationData,NULL))
{
printf("receive ok");
}
else
{
printf("receiv error %d",WSAGetLastError());
}

}
return 0;
}void CreateWorkThread(LPVOID hCompPort)
{
SYSTEM_INFO systemInfo;
GetSystemInfo(& systemInfo);
int i;
DWORD threadID;
HANDLE threadHandle;
for(i=0;i < systemInfo.dwNumberOfProcessors*2;i++)
{
threadHandle = CreateThread(NULL,0,ServerWorkerThread,hCompPort,0,&threadID);
CloseHandle(threadHandle);
}
}DWORD WINAPI ServerWorkerThread(LPVOID completionPortID)
{
HANDLE hCompPort = (HANDLE)completionPortID;
//处理消息
LP_PER_IO_OPERATION_DATA perIoOperationData;
LP_PER_HANDLE_DATA perHandleData; DWORD dwTransCount = 0;
while(true)//获取消息队列
{
printf("work thread");

if(GetQueuedCompletionStatus(hCompPort,&dwTransCount,(LPDWORD)&perHandleData,(LPOVERLAPPED *)&perIoOperationData,INFINITE) == 0)
{
 printf(" GetQueuedCompletionStatus failed with error %d\n " , WSAGetLastError());
             }
else
{
printf("get message ok transnum %d",dwTransCount);

}
switch(perIoOperationData->stClientToServer.iMessageType)
{
case REGISTER:
perIoOperationData->stClientToServer.message.loginmember.userName;
break;
case LOGIN:
printf("user name is %s",perIoOperationData->stClientToServer.message.loginmember.userName);
break;
case LOGOUT:
break;

}
printf("type is %d and userName is %s",perIoOperationData->stClientToServer.iMessageType,perIoOperationData->stClientToServer.message.loginmember.userName);
printf("receive io data %d",perIoOperationData->bytesRecv);
return 0;

}}

解决方案 »

  1.   

    客户端代码MFC的
    一个奇怪的问题是,客户端WSASend 的  numberOfBytesSent 值为 0,yge 
    void CClientDlg::OnButton1() 
    {
    // TODO: Add your control notification handler code here
    //绑定端口
    WSADATA wsaData; if(::WSAStartup(MAKEWORD(2,2),&wsaData) == 0)
    {
    //AfxMessageBox("INIT OK");
    }
    SOCKET sClient;
    sClient = ::WSASocket(AF_INET,SOCK_STREAM,0,0,0,WSA_FLAG_OVERLAPPED);
    if(sClient < 0)
    {
    AfxMessageBox("Make socket error");
    }
    //连接服务器
    CString s;
    SOCKADDR_IN saRemote;
    saRemote.sin_family = AF_INET;
    saRemote.sin_addr.S_un.S_addr = ::inet_addr(SERVER_IP);
    saRemote.sin_port = ::htons(SERVER_PORT);
        if(::connect(sClient,(SOCKADDR *)&saRemote,sizeof(saRemote)) == 0)
    {
    //AfxMessageBox("connect ok"); }
    else
    {

    s.Format("connect error%d",::WSAGetLastError());
    AfxMessageBox(s);
    } //发送用户名密码
    stMessage clientToServerMessage;
    clientToServerMessage.iMessageType = LOGIN;
    char userName[10];
    char password[10];
    GetDlgItemText(IDC_EDIT1,userName,10);
    GetDlgItemText(IDC_EDIT2,password,10); ::strncpy(clientToServerMessage.message.loginmember.userName,userName,10);
    ::strncpy(clientToServerMessage.message.loginmember.password,password,10);
    LP_PER_IO_OPERATION_DATA pPerIoOperationData = (LP_PER_IO_OPERATION_DATA)::GlobalAlloc(GPTR,sizeof(PER_IO_OPERATION_DATA)); ZeroMemory(&(pPerIoOperationData->ol),sizeof(pPerIoOperationData->ol));
    pPerIoOperationData->stClientToServer = clientToServerMessage;
    pPerIoOperationData->dataBuf.buf = pPerIoOperationData->buffer;
    pPerIoOperationData->dataBuf.len = BUFF_SIZE;   

    DWORD dwFlags = 0;
    DWORD numberOfBytesSent;
    if(::WSASend(sClient,(LPWSABUF)&pPerIoOperationData->buffer,1,&numberOfBytesSent,dwFlags,(LPWSAOVERLAPPED)pPerIoOperationData,NULL)  == SOCKET_ERROR)
    {
    s.Format("wsasend with error: %d",WSAGetLastError());
    AfxMessageBox(s);
    }
    else
    {
    s.Format("wsasend data num is: %d",numberOfBytesSent);
    AfxMessageBox(s);
    }
    }
      

  2.   

    把断点设到GetQueuedCompletionStatus后面,然后仔细看各参数的值。
      

  3.   

    我晕,GetQueuedCompletionStatus 在线程里面,设的断点没用,运行到哪些没有任何参数
      

  4.   

    在调试时,客户端WSASend 时,LP_PER_IO_OPERATION_DATA 里的 overlapped 里的内容为,error:不能执行表达式,
    填充时用的名令是 ZeroMemory(&pPerIoOperationData->ol,sizeof(OVERLAPPED));
    基于MFC的
    其中 
    pPerIoOperationData结构体为 
    typedef struct{
    OVERLAPPED ol;
    WSABUF dataBuf;
    char buffer[BUFF_SIZE];
    DWORD bytesSend;
    DWORD bytesRecv;
    stMessage stClientToServer;
    }PER_IO_OPERATION_DATA,*LP_PER_IO_OPERATION_DATA;
    typedef struct
    {
    SOCKET socket;
    }PER_HANDLE_DATA,*LP_PER_HANDLE_DATA;
      

  5.   

    呵呵,谢谢 
    unsigned(僵哥(发站内消息,请附上链接或问题说明,否则不予回) 
    因为我是 刚学VC的,到今天,这周是第三周开始,请你加我QQ 24645955 好吗,或者你留下QQ
    或MSN 我加你,向你请教一下,我实在找不到哪里出问题了
      

  6.   

    一般直接使用WindowsIOCP编程是在学习IOCP的内在机制,当了解了IOCP的内在机制后,最好不要直接使用Windows提供的接口进行IOCP的开发,请使用成熟的框架,如ACE的Proactor或boost的aio,这样一般能保证程序的稳定性和程序的扩展性,只不过降低了一点性能