Winsocks 2异步问题

Winsocks 2 Asynchronous Problem

本文关键字:问题 异步 Winsocks      更新时间:2023-10-16

我试图在异步模式下使用winsock2。我能够从客户机发送消息到服务器,但不能从服务器发送消息到客户机。当我在客户端调用recv时,缓冲区中没有收到任何内容。

这是我的客户端代码

ClientSocket::ClientSocket (HWND& pHwnd)
{   
    WSADATA     wsdata;
    vSzIncoming     =   0;
    int error = WSAStartup (MAKEWORD(2,2), &wsdata);
    vSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
    error = WSAAsyncSelect (vSocket, pHwnd, WM_SOCKET, (FD_CLOSE | FD_READ));
    vHwnd           =   pHwnd;
    vIsConnected    =   false;
}
bool ClientSocket::ConnectToServer () 
{       
SockAddr.sin_port           =   htons (20000);
SockAddr.sin_family         =   AF_INET;
SockAddr.sin_addr.s_addr    =   inet_addr ("127.0.0.1");
if(connect (vSocket, (LPSOCKADDR)(&SockAddr), sizeof (SockAddr)) == SOCKET_ERROR) {

    vIsConnected = false;
    return false;
}
vIsConnected = true;
return true;
}
void ClientSocket::SendMsg (const MessageGenerator& pMessageGenerator)
{   
    send(vSocket, pMessageGenerator.GetMessage ().Buffer (), pMessageGenerator.GetLength (), 0);
}
char * ClientSocket::ReceiveMsg ()
{   
char temp[1024];
ZeroMemory (temp, sizeof (temp));
int inDataLength = recv (vSocket,
                    (char*)temp,
                     sizeof (temp) / sizeof (temp [0]),
                     0);
return temp;
}

这是服务器代码

WSADATA WsaDat;
        int nResult=WSAStartup(MAKEWORD(2,2),&WsaDat);

        Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        SOCKADDR_IN SockAddr;
        SockAddr.sin_port=htons(nPort);
        SockAddr.sin_family=AF_INET;
        SockAddr.sin_addr.s_addr=htonl(INADDR_ANY);
        if(bind(Socket,(LPSOCKADDR)&SockAddr,sizeof(SockAddr))==SOCKET_ERROR)
        {
        }
        nResult=WSAAsyncSelect(Socket,
                hWnd,
                WM_SOCKET,
                (FD_CLOSE|FD_ACCEPT|FD_READ));
        if(listen(Socket,(1))==SOCKET_ERROR)
        {
        }

//发送部分
String str ="1;yahoo;|";
send(Socket,str.Buffer(),str.GetLength(),0);

//接收部分
case WM_SOCKET:
    {
        switch(WSAGETSELECTEVENT(lParam))
        {
            case FD_READ:
            {
                char szIncoming[1024];
                ZeroMemory(szIncoming,sizeof(szIncoming));
                int inDataLength=recv(Socket,
                    (char*)szIncoming,
                    sizeof(szIncoming)/sizeof(szIncoming[0]),
                    0);
                String str(szIncoming);
                wcsncat(szHistory,str.GetTChar(),inDataLength);
                wcscat(szHistory,L"rn");

                SendMessage(hEditIn,
                    WM_SETTEXT,
                    sizeof(szIncoming)-1,
                    reinterpret_cast<LPARAM>(&szHistory));
            }
case FD_ACCEPT:
            {
                int size=sizeof(sockaddr);
                Socket=accept(wParam,&sockAddrClient,&size);                
            }

请帮帮我

很难说你的问题在哪里。最好的解决方案是系统地清除所有可能的障碍:

  • 查看recv的返回值。如果有一个错误,你的缓冲区是不变的,所以一个"空"字符串返回。
  • 检查服务器端是否使用了正确的客户端套接字。您使用"Socket"变量名的次数太多。最好是区分客户端套接字和服务器套接字。另外:如何存储客户端套接字?这是全局变量还是静态变量?您确定这个值是正确的吗?(这一点主要是为您的服务器端代码)
  • 用日志扩展你的代码,这样你就可以跟踪客户端和服务器端发生的事情。调试器也可以帮助你。

还有一个相当大的错误,你应该立即纠正在你的代码:

char * ClientSocket::ReceiveMsg ()
{   
    char temp[1024];
    ZeroMemory (temp, sizeof (temp));
    int inDataLength = recv (vSocket,
                        (char*)temp,
                         sizeof (temp) / sizeof (temp [0]),
                         0);
    return temp; // ** don't return a local memory "object" **
}

不要那样做。要么使用_strdup返回一个副本,要么使用并返回你的"String"对象。当然,如果使用_strdup,调用者必须使用适当的函数(free)释放内存。啊,是的,第三种可能性是只期望缓冲区作为一个参数,就像recv已经做的那样。