DWORD __stdcall CCompletionPort::CompletionRoutine(LPVOID lParam)
{
HANDLE hCompletionPort  = (HANDLE)lParam;
BOOL bRet  = 0;
LPOVERLAPPED lpOverlapped  = NULL;
LPCompletionKey lpCompletionKey  = NULL;
LPOverlappedData lpOverlappedData = NULL;
DWORD dwNumOfBytes  = 0;
DWORD dwRecvBytes  = 0;
DWORD dwSendBytes  = 0;
DWORD dwFlags  = 0;
CDealWithMsg dealmsg; for(;;)
{
bRet = GetQueuedCompletionStatus(
hCompletionPort,
&dwNumOfBytes, 
(LPDWORD)&lpCompletionKey, 
(LPOVERLAPPED*)&lpOverlappedData, 
INFINITE
); if(bRet == false && &(lpOverlappedData->Overlapped) == NULL)
{
cout << "GetQueuedCompletionStatus error. Error code: " << GetLastError() << endl;
return 1;
}
else if(bRet == false && &(lpOverlappedData->Overlapped) != NULL)
{
cout << (unsigned int)lpCompletionKey->socket << " 非法退出" << endl; if(closesocket(lpCompletionKey->socket) == SOCKET_ERROR)
{
cout << "关闭套接字失败" << endl;
} GlobalFree(lpOverlappedData);
GlobalFree(lpCompletionKey);
}
else if(dwNumOfBytes == 0)
{
cout << (unsigned int)lpCompletionKey->socket << " 已关闭端口" << endl; if(closesocket(lpCompletionKey->socket) == SOCKET_ERROR)
{
cout << "关闭套接字失败" << endl;
} GlobalFree(lpOverlappedData);
GlobalFree(lpCompletionKey); continue;
}
else
{
if(lpOverlappedData->bOperationType == RECV_POSTED)
{
CHicqMsg* phicqmsg = (CHicqMsg*)lpOverlappedData->wsaBuf.buf;
phicqmsg->SetSocket(lpCompletionKey->socket);

dealmsg.DealWithMsg(phicqmsg, lpOverlappedData);
}
else if(lpOverlappedData->bOperationType == SEND_POSTED)
{
}
// waitting next receive
dealmsg.RecvMsg(lpCompletionKey->socket, lpOverlappedData);
} } return 0;
}
CDealWithMsg是另外写出一个处理数据的类。
第一次发送数据,就会进入死循环,如果我只是收,就没有问题,我发时是用的
int CDealWithMsg::DealWithMsg(CHicqMsg* phicqmsg, LPOverlappedData lpOverlappedData)
{
CHsocket hsocket(phicqmsg->GetSocket()); switch(phicqmsg->GetCmd())
{
case HICQ_CMD_LOGIN:
if(!Login(phicqmsg->GetUserID(), phicqmsg->GetSocket(), hsocket.getremoteaddr(), 
hsocket.getremoteport(), phicqmsg->GetPassWord()))
{
phicqmsg->SetCmd(HICQ_CMD_LOGOUT);
phicqmsg->SetFlags(HICQ_FLAG_INVALID_USERNAME); SendMsg(phicqmsg->GetSocket(), lpOverlappedData);
break;
}// login failed // login success
cout << phicqmsg->GetUserID() << " has logined" << endl;

phicqmsg->SetCmd(HICQ_CMD_LOGIN);
phicqmsg->SetFlags(HICQ_FLAG_LOGIN_SUCCESS);

SendMsg(phicqmsg->GetSocket(), lpOverlappedData);
break;
      。。
 }
int CDealWithMsg::SendMsg(SOCKET socket, LPOverlappedData lpOverlappedData)
{
DWORD dwSendBytes  = 0;
DWORD dwFlags  = 0; ZeroMemory(&(lpOverlappedData->Overlapped), sizeof(OVERLAPPED));
lpOverlappedData->bOperationType = SEND_POSTED; return WSASend(
socket,
&(lpOverlappedData->wsaBuf),
1, 
&dwSendBytes,
dwFlags, 
&(lpOverlappedData->Overlapped),
NULL
);
}int CDealWithMsg::RecvMsg(SOCKET socket, LPOverlappedData lpOverlappedData)
{
DWORD dwSendBytes  = 0;
DWORD dwFlags  = 0; ZeroMemory(&(lpOverlappedData->Overlapped), sizeof(OVERLAPPED));
lpOverlappedData->wsaBuf.len = MAXLEN;
lpOverlappedData->wsaBuf.buf = lpOverlappedData->buff;
lpOverlappedData->bOperationType = RECV_POSTED; return WSARecv(
socket,
&(lpOverlappedData->wsaBuf),
1, 
&dwSendBytes,
&dwFlags, 
&(lpOverlappedData->Overlapped),
NULL
);
}
enum { ACCEPT_POSTED, RECV_POSTED, SEND_POSTED };typedef struct st_CompletionKey
{
SOCKET socket;
}CompletionKey, *LPCompletionKey;typedef struct st_OverlappedData
{
OVERLAPPED Overlapped;
WSABUF    wsaBuf;
char    buff[MAXLEN];
BOOL    bOperationType;
}OverlappedData,*LPOverlappedData;
谁能告诉我要怎么发数据啊,在服务器端,谢谢

解决方案 »

  1.   

    我就是投的一个wsasend啊,可是不行,要是行,也就不会有这个贴子了:)
      

  2.   

    如果把
    DealWithMsg(...)里的
    phicqmsg->SetCmd(HICQ_CMD_LOGIN);
    phicqmsg->SetFlags(HICQ_FLAG_LOGIN_SUCCESS);
    SendMsg(phicqmsg->GetSocket(), lpOverlappedData);
    去掉,即不发消息,就没有问题。
      

  3.   

    这是我一个WsaSend的处理,希望对你有用!
    #define SENDOPTION 1
    #define RECVOPTION 2
    typedef struct
    {
    OVERLAPPED Overlapped;
    WSABUF DataBuf;
    CHAR Buffer[DATA_BUFSIZE];
    DWORD BytesSEND;
    DWORD BytesRECV;
    DWORD Option;
    }PER_IO_OPERATION_DATA,*LPPER_IO_OPERATION_DATA;
    int CServerSocket::SendMsg(SOCKET cliSocket,char *buf)
    {
    HANDLE ComPort=CompletionPort;
    DWORD dwBytesTransferred;
    DWORD dwBytesSend,dwBytesRecvd;
    DWORD Flags=0;
    PER_IO_OPERATION_DATA* PerIOData=new PER_IO_OPERATION_DATA;
    PER_HANDLE_DATA* PerHandleData=new PER_HANDLE_DATA;

             Flags = 0;

             ZeroMemory(&(PerIOData->Overlapped), sizeof(OVERLAPPED));

     strncpy(PerIOData->Buffer ,"hello world",20);
             PerIOData->DataBuf.len = DATA_BUFSIZE;
             PerIOData->DataBuf.buf = PerIOData->Buffer;
    PerIOData->Option=SENDOPTION;
             if (WSASend(cSocket[0], &(PerIOData->DataBuf), 1, &dwBytesSend, Flags,
                &(PerIOData->Overlapped), NULL) == SOCKET_ERROR)
             {
                if (WSAGetLastError() != ERROR_IO_PENDING)
                {
                   printf("WSARecv() failed with error %d\n", WSAGetLastError());
                   return 0;
                }
             }
    }DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
    {
    HANDLE ComPort=(HANDLE)CompletionPortID;
    DWORD dwBytesTransferred;
    DWORD dwBytesSend,dwBytesRecvd;
    DWORD Flags=0;
    LPPER_HANDLE_DATA PerHandleData;  
    LPPER_IO_OPERATION_DATA PerIOData;
    while(TRUE)
    {
    if(GetQueuedCompletionStatus(ComPort,&dwBytesTransferred,(LPDWORD)&PerHandleData,
    (LPOVERLAPPED*)&PerIOData,INFINITE)==0)
    {
    int nErrorCode=GetLastError();
    AfxMessageBox("GetQueue Failed");
    return -1;
    }
    if(dwBytesTransferred==0)
    {
    closesocket(PerHandleData->Socket);
    delete  PerIOData;
    delete PerHandleData;
    }
    if(PerIOData->Option==SENDOPTION)
    {
    AfxMessageBox("Send SuccessFul");
    continue;
    }
    }
      

  4.   

    HunterForPig(留着口水的猪) :
    很感谢你的回答,看完你的代码,似乎还是找不到答案,你能否把ServerWorkerThread里的代码贴全,或是把你整个程序发给我,谢谢![email protected]
      

  5.   

    看看这个例子http://elssann.51.net/class.rar
      

  6.   

    建议楼主看看wsasend返回值是什么。
      

  7.   

    我在处理收到的消息时,又要发消息,那投下一个wsarecv是在wsasend之后还是之前啊
    比如收到客户发来的消息请求得到好友列表,就要马上给他发好友列表。
      

  8.   

    stavck(关未明) :
    你提供的不存在哦:)
      

  9.   

    rabo(不哭死人): 你说的猫王是否为sevencat
    QQ里倒是有他,但不常在线,哦,隐身了,明天请教一下:)
      

  10.   

    其实关于WSASend的处理已经全了
    下面那些代码是投递WSARecv请求!
      

  11.   

    HunterForPig(留着口水的猪):
    我发现我的程序现在可能就是wsasend & wsarecv没有投好,前几天搞好了,可我觉得有问题,改了一下,现以又有问题,我觉得以前那样不好,
    能否把你的代码参考一下。
      

  12.   

    #define PORT 5150
    #define DATA_BUFSIZE 4096
    #define SENDOPTION 1
    #define RECVOPTION 2
    CWinThread* pServerListenThread=NULL;
    SOCKET lSocket,cSocket[64];
    HANDLE CompletionPort;DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID);
    char BUF[4096];typedef struct
    {
    OVERLAPPED Overlapped;
    WSABUF DataBuf;
    CHAR Buffer[DATA_BUFSIZE];
    DWORD BytesSEND;
    DWORD BytesRECV;
    DWORD Option;
    }PER_IO_OPERATION_DATA,*LPPER_IO_OPERATION_DATA; typedef struct
    {
    SOCKET Socket;
    //SOCKADDR addr;
    }PER_HANDLE_DATA,*LPPER_HANDLE_DATA;CServerSocket::CServerSocket()
    {
    }
    int CServerSocket::StartListen(UINT& Port)
    {
    m_nPort=Port;

    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
    {
    AfxMessageBox("Startup Failed");
    return -1;
    }




    lSocket=socket(AF_INET,SOCK_STREAM,0);

    SOCKADDR_IN servAddr;
    servAddr.sin_family=AF_INET;
    servAddr.sin_addr.s_addr=htonl(INADDR_ANY);
    servAddr.sin_port=htons(Port);int nRet=0;
    if((nRet=bind(lSocket,(SOCKADDR*)&servAddr,sizeof(servAddr)))==SOCKET_ERROR)
    {
    AfxMessageBox("bind socket Error");
    return -1;
    } //创建一完成端口,!

    CompletionPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0); SYSTEM_INFO SystemInfo;
    GetSystemInfo(&SystemInfo);

    for(int i=0;i<(int)SystemInfo.dwNumberOfProcessors*2;i++)//每个comio创建两个线程
    {
    HANDLE ThreadHandle;
    if((ThreadHandle=CreateThread(NULL,0,ServerWorkerThread,CompletionPort,0,NULL))==NULL)
    {
    int errorCode=GetLastError();
    return -1;
    }
    CloseHandle(ThreadHandle);
    } if(listen(lSocket,5)==SOCKET_ERROR)
    {
    AfxMessageBox("listen socket Failed");
    return -1;
    }pServerListenThread=AfxBeginThread(_ServerListenThread,this);
    }UINT _ServerListenThread(LPVOID lParam)
    {
    CServerSocket *pServ=(CServerSocket*)lParam;
    SOCKET clientSocket;
    SOCKADDR_IN clientAddr;
    PER_HANDLE_DATA *PerHandleData=NULL;;
    PER_IO_OPERATION_DATA  *PerIOData=NULL;
    DWORD Flags=0;
    int addrLen=sizeof(SOCKADDR_IN); int i=0;
    while(TRUE)
    {
    clientSocket=accept(lSocket,(SOCKADDR*)&clientAddr,&addrLen);
    if(clientSocket==SOCKET_ERROR)
    {
    int nErrorCode=GetLastError();
    AfxMessageBox("Accept failed");
    return -1;
    }cSocket[i]=clientSocket;
    i++;
    PerHandleData=new PER_HANDLE_DATA;
    PerHandleData->Socket=clientSocket;
    if(CreateIoCompletionPort((HANDLE)clientSocket,CompletionPort,(DWORD)PerHandleData,0)==NULL)
    {
    int nErrorCode=GetLastError();
    AfxMessageBox("关联句柄与端口错误");
    return -1;
    }
    PerIOData=new PER_IO_OPERATION_DATA;
    ZeroMemory(&PerIOData->Overlapped ,sizeof(OVERLAPPED));
    PerIOData->Option =RECVOPTION;

    PerIOData->DataBuf.buf =BUF;
    //PerIOData->DataBuf.buf =PerIOData->Buffer;  
    PerIOData->DataBuf.len =DATA_BUFSIZE;
    PerIOData->BytesRECV=0;
    PerIOData->BytesSEND=0;
    Flags=0;
    if(WSARecv(clientSocket,&PerIOData->DataBuf,1,&PerIOData->BytesRECV,&Flags,
    &PerIOData->Overlapped,NULL)==SOCKET_ERROR)
    {
    if(WSAGetLastError() != WSA_IO_PENDING) 
    {
    int nErrorCode=GetLastError();
    AfxMessageBox("第一次投递WSARecv错误");
    return -1;
    }
    } }
    return 0;
    }
    DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
    {
    HANDLE ComPort=(HANDLE)CompletionPortID;
    DWORD dwBytesTransferred;
    DWORD dwBytesSend,dwBytesRecvd;
    DWORD Flags=0;
    LPPER_HANDLE_DATA PerHandleData;  
    LPPER_IO_OPERATION_DATA PerIOData;
    while(TRUE)
    {
    if(GetQueuedCompletionStatus(ComPort,&dwBytesTransferred,(LPDWORD)&PerHandleData,
    (LPOVERLAPPED*)&PerIOData,INFINITE)==0)
    {
    int nErrorCode=GetLastError();
    AfxMessageBox("GetQueue Failed");
    return -1;
    }
    if(dwBytesTransferred==0)
    {
    closesocket(PerHandleData->Socket);
    delete  PerIOData;
    delete PerHandleData;
    }
    if(PerIOData->Option==SENDOPTION)
    {
    AfxMessageBox("Send SuccessFul");
    continue;
    }
    if(PerIOData->Option==RECVOPTION)
    {
    AfxMessageBox((LPCTSTR)PerIOData->DataBuf.buf);

    PerIOData->BytesRECV = 0;        
             Flags = 0;
             ZeroMemory(&(PerIOData->Overlapped), sizeof(OVERLAPPED));
    PerIOData->Option=RECVOPTION;
             PerIOData->DataBuf.len = DATA_BUFSIZE;
             PerIOData->DataBuf.buf = PerIOData->Buffer;         if (WSARecv(PerHandleData->Socket, &(PerIOData->DataBuf), 1, &dwBytesRecvd, &Flags,
                &(PerIOData->Overlapped), NULL) == SOCKET_ERROR)
             {
                if (WSAGetLastError() != ERROR_IO_PENDING)
                {
                   printf("WSARecv() failed with error %d\n", WSAGetLastError());
                   return 0;
                }
             }
    } }
    }
    int CServerSocket::SendMsg(SOCKET cliSocket,char *buf)
    {
    HANDLE ComPort=CompletionPort;
    DWORD dwBytesTransferred;
    DWORD dwBytesSend,dwBytesRecvd;
    DWORD Flags=0;
    PER_IO_OPERATION_DATA* PerIOData=new PER_IO_OPERATION_DATA;
    PER_HANDLE_DATA* PerHandleData=new PER_HANDLE_DATA;

             Flags = 0;

             ZeroMemory(&(PerIOData->Overlapped), sizeof(OVERLAPPED));

     strncpy(PerIOData->Buffer ,"hello world",20);
             PerIOData->DataBuf.len = DATA_BUFSIZE;
             PerIOData->DataBuf.buf = PerIOData->Buffer;
    PerIOData->Option=SENDOPTION;
             if (WSASend(cSocket[0], &(PerIOData->DataBuf), 1, &dwBytesSend, Flags,
                &(PerIOData->Overlapped), NULL) == SOCKET_ERROR)
             {
                if (WSAGetLastError() != ERROR_IO_PENDING)
                {
                   printf("WSARecv() failed with error %d\n", WSAGetLastError());
                   return 0;
                }
             }
    }