两次使用时,recv函数失败

时间:2014-09-26 22:43:20

标签: c++ sockets winapi network-programming

大家好我所有我一直在从一个简单的客户端接收两个地址然后使用异步套接字和WINAPI打印它们的服务器,到目前为止我已经设置了窗口并且能够接受连接但是当我尝试向服务器发送两条消息时,它只收到一条消息而第二条消息失败。这是代码:

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));

    }
}

1 个答案:

答案 0 :(得分:2)

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

您不应在代码中使用幻数。 1111是WM_USER+87,因此您应该将其分配给常量,以便更容易阅读,例如:const UINT WM_SOCKETMSG = WM_USER + 87;,然后在case语句中使用该名称,例如:{{1} }。

您的套接字消息处理程序在调用case WM_SOCKETMSG:之前正在调用socket()accept()分配并返回一个新套接字。因此,每次收到accept()通知时,您都会泄漏套接字。如果多个客户端碰巧连接,那么您将丢失对旧套接字的跟踪,因为您使用单个变量来跟踪它们。

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

您需要设计一个协议来控制数据流,您不能只是抛出任意数据。我严重怀疑你想要4KB用户名并浪费大约3KB的IP地址。您需要划分传输的值,不仅要减少带宽使用,还要减少保存它们所需的内存。对于像您所示的简单内容,您可以使用LF字符分隔值。然后,您可以在处理滚动缓冲区时查找该字符。

最后,你根本没有处理错误。你需要这样做。

尝试更像这样的东西:

WSAEWOULDBLOCK