2014-09-26 142 views
0

您好所有我一直在努力,从一个简单的客户端接收这两个地址,然后使用异步Socket和WINAPI打印出来一个服务器上,到目前为止,我已经设置了窗口,并已能够接受连接,但是当我尝试向服务器发送两条消息时,它只收到一条消息,第二条消息失败。下面是代码:recv函数失败

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    HWND hEdit = NULL; 
    int len = sizeof(Server); 
    switch (msg) 
    { 
    case WM_CREATE: 


     hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", 
      WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 
      0, 0, WIDTH, HEIGHT, hwnd, (HMENU)IDC_MAIN_EDIT, GetModuleHandle(NULL), NULL); 
     break; 
    case WM_DESTROY: 
     PostQuitMessage(0); 

     break; 
    case 1111: 

     if (LOWORD(lParam) == FD_ACCEPT) 
     { 

      socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
      socket = accept(sListen, (SOCKADDR*)&Server, &len); 


      print_line(hwnd, "IT WAS ACCEPTED!!!!!!!!\r\n"); 
     } 
     if (LOWORD(lParam) == FD_CLOSE) 
     { 
      print_line(hwnd, "Client left the server!\r\n"); 

     } 
     if (LOWORD(lParam) == FD_READ) 
     { 
      char NICK[4096] = { 0 }; 
      char IP[4096] = { 0 }; 
      ZeroMemory(NICK, strlen(NICK)); 
      ZeroMemory(IP, strlen(IP)); 
      if (recv(socket, IP, sizeof(IP), NULL) == INVALID_SOCKET)//get the IP address 
      { 
       print_line(hwnd, "Failed to recieve IP Address from socket!"); 
       print_line(hwnd, "\r\n"); 
      } 
      if (recv(socket, NICK, sizeof(NICK), NULL) == INVALID_SOCKET)//get the Nickname 
      { 
       print_line(hwnd, "Failed to recieve nickname from socket!"); 
       print_line(hwnd, "\r\n"); 
      } 
      //prints the Username and IP address to the window screen 
      print_line(hwnd, "Username: "); 
      print_line(hwnd, NICK); 
      print_line(hwnd, "\r\n"); 
      print_line(hwnd, "IP Address: "); 
      print_line(hwnd, IP); 
      print_line(hwnd, "\r\n"); 

     } 
     break; 
    default: 



     HWND hEdit; 
     RECT rcClient; 

     GetClientRect(hwnd, &rcClient); 

     hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT); 
     SetWindowPos(hEdit, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER); 


     return (DefWindowProc(hwnd, msg, wParam, lParam)); 

    } 
} 
+0

检查第二个呼叫之前的错误,并张贴结果 – 2014-09-26 22:48:02

+0

@MarcoA。你的意思是第一个recv函数调用?如果这是你的意思,我已经检查过,并没有错误,它打印的IP地址 – user3097544 2014-09-26 22:49:29

+0

对不起,我的意思是:检查第二次通话后的错误,所以你可以看到更详细的错误 – 2014-09-26 22:55:19

回答

2

想必您使用WSAAsyncSelect(),但你没有显示,创建监听套接字或为其注册消息处理程序的代码。

你不应该在你的代码中使用幻数。 1111 WM_USER+87,所以你应该将它赋值给一个常数,因此更容易阅读,例如:const UINT WM_SOCKETMSG = WM_USER + 87;,然后在您的case语句中使用该名称,例如:case WM_SOCKETMSG:

您的插座消息处理程序是正确的调用accept()之前调用socket()accept()分配并返回一个新的套接字。因此,每次收到FD_ACCEPT通知时都会泄漏套接字。如果有多个客户端发生连接,则由于您使用单个变量来跟踪所有旧套接字,因此您将丢失旧套接字的跟踪。

你没有考虑到TCP是一个字节流,比你问recv()可能返回较少的字节。它返回当前可用的任何数据,但不会超过您提供的缓冲区的大小。你正在使用一个异步套接字,但是你编写了你的​​阅读代码,就好像你在使用一个同步套接字(而且即使这样,你显示的逻辑有时也会失败)。如果当前没有数据可用,则recv()将失败,并显示WSAEWOULDBLOCK错误,您不处理该错误。每当新数据到达时,您需要将其读入滚动缓冲区,然后根据需要从该缓冲区中仅提取完成的数据,并在缓冲区中留下不完整的数据,以便随后的读取可以完成。

你需要周围设计了一个协议来控制数据流,你不能随便扔任意数据。我严重怀疑你想要4KB用户名,并浪费〜3KB的IP地址。您需要划定要传输的值,不仅可以减少带宽使用量,还可以减少保存它们所需的内存。对于像你所显示的那样简单的事情,你可以用一个LF字符来分隔这些值。您可以在处理滚动缓冲区时查找该字符。

最后,你是不是交给错误的。你需要这样做。

尝试一些更喜欢这个:

#include <map> 
#include <string> 

std::map<SOCKET, std::string> ClientBuffers; 
typedef std::map<SOCKET, std::string>::iterator BufferIterator; 

const UINT WM_SOCKETMSG = WM_USER + 87; 

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    ... 
    switch (msg) 
    { 
     ... 
     case WM_SOCKETMSG: 
     { 
      SOCKET socket = (SOCKET) wParam; 
      int event = WSAGETSELECTEVENT(lParam); 
      int error = WSAGETSELECTERROR(lParam); 

      switch (event) 
      { 
       case FD_ACCEPT: 
       { 
        if (error == 0) 
        { 
         sockaddr_in clientaddr = {0}; 
         int len = sizeof(clientaddr); 

         if (accept(socket, (SOCKADDR*)&clientaddr, &len) != INVALID_SOCKET) 
         { 
          print_line(hwnd, "A client connected to the server!\r\n"); 
          break; 
         } 

         error = WSAGetLastError(); 
        } 

        print_line(hwnd, "Error accepting a client!\r\n"); 
        // handle the error on the reported socket as needed... 

        break; 
       } 

       case FD_CLOSE: 
       { 
        if (error == 0) 
         print_line(hwnd, "A client left the server!\r\n"); 
        else 
         print_line(hwnd, "A client connection was lost unexpectedly!\r\n"); 

        BufferIterator i = ClientBuffers.find(socket); 
        if (i != ClientBuffers.end()) 
         ClientBuffers.erase(i); 

        break; 
       } 

       case FD_READ: 
       { 
        char buf[1024]; 

        int numRead = recv(socket, buf, sizeof(buf), NULL); 
        if (numRead == SOCKET_ERROR) 
        { 
         if (WSAGetLastError() != WSAEWOULDBLOCK) 
         { 
          print_line(hwnd, "Failed to read from a client!\r\n"); 
          // handle the error on the reported socket as needed... 
         } 
         break; 
        } 

        if (numRead == 0) 
         break; 

        std::string &buffer = ClientBuffers[socket]; 
        buffer += std::string(buf, numRead); 

        std::string::size_type idx1 = buffer.find('\n'); 
        if (idx1 == std::string::npos) 
         break; // wait for more data 

        std::string::size_type idx2 = buffer.find('\n', idx1+1); 
        if (idx2 == std::string::npos) 
         break; // wait for more data 

        std::string IP = buffer.substr(0, idx1); 
        std::string NICK = buffer.substr(idx1+1, idx2-idx1-1); 
        buffer.erase(0, idx2+1); 

        //prints the Username and IP address to the window screen 
        print_line(hwnd, "Username: "); 
        print_line(hwnd, NICK.c_str()); 
        print_line(hwnd, "\r\n"); 
        print_line(hwnd, "IP Address: "); 
        print_line(hwnd, IP.c_str()); 
        print_line(hwnd, "\r\n"); 

        break; 
       } 
      } 

      break; 
     } 
    } 
    ... 
}