【问题标题】:asynchronous udp server client application异步 udp 服务器客户端应用程序
【发布时间】:2013-04-16 20:28:37
【问题描述】:

我正在尝试制作一个异步 UDP 聊天应用程序,目前只有一个客户端和服务器。

当我运行我的服务器时,会显示很多冗余数据。之后,当输入一些文本时,

发送文件时出错!

显示出来。

有人可以看看代码并告诉我哪里出错了吗?

服务器:
u_long iMode=1; ioctlsocket(sd,FIONBIO,&iMode); int n=sd+1;

fd_set readfds,writefds;
while(1)
{
    FD_ZERO(&readfds);
    FD_ZERO(&writefds);
    FD_SET(sd,&readfds);
    FD_SET(sd,&writefds);

    int rv = select(n, &readfds, &writefds, NULL, NULL);
    if(rv==-1)
    {
        printf("Error in Select!!!\n");
        exit(0);
    }
    if(rv==0)
    {
        printf("Timeout occurred\n");
    }
    if (FD_ISSET(sd, &readfds))
    {
        FD_CLR(sd,&readfds);
        int client_length = (int)sizeof(struct sockaddr_in);
        memset(&buffer,0,sizeof(buffer));
        int bytes_received = recvfrom(sd, buffer,SIZE, 0, (struct sockaddr *)&client, &client_length);
        if (bytes_received < 0)
        {
            fprintf(stderr, "Could not receive datagram.\n");
            closesocket(sd);
            WSACleanup();
            exit(0);
        }
    }

    printf("\nClient says: %s",buffer);
    printf("\nWrite :");

    fgets(buffer,SIZE,stdin);
    if(FD_ISSET(sd,&writefds))
    {
        FD_CLR(sd,&writefds);
        int client_length = (int)sizeof(struct sockaddr_in);
        if(sendto(sd, buffer,strlen(buffer), 0, (struct sockaddr *) &client,client_length)<0)
        {
            printf("Error sending the file! \n");
            exit(1);
        }
    }
}
closesocket(sd);
WSACleanup();

return 0;
}

【问题讨论】:

  • 首先,您不需要从集合中手动清除套接字(例如 FD_CLR 调用)。在select 调用之前,您无论如何都要重置设置。
  • 其次,不要在您的memset 通话中使用&amp;buffer。如果buffer 是一个指针,它不会做它认为的事情。此外,如果 buffer 是一个指针,那么 sizeof(buffer) 将返回 指针 的大小,而不是它所指向的大小。
  • 调用 sendto 失败后 WSAGetLastError 返回什么?
  • @JoachimPileborg,buffer 是数组的名称...
  • 最后,您显示的代码中没有任何地方可以打印"Error Transmitting data"。这是您向我们展示的正确代码吗?

标签: c sockets udp


【解决方案1】:

我发现了一个问题。这一行:

int rv = select(n, &readfds, &writefds, NULL, NULL);

几乎总是在 readfds 为空的情况下立即返回。但是 writefds 几乎总是设置为“sd”套接字,表明它已准备好写入/发送。

因此,您的代码正确地跳过了调用 recvfrom() 的尝试,但没有什么能阻止它落入发送代码路径。所有变量,如 client、client_length 和 buffer,在那时可能都未初始化。或者更糟的是,缓冲区和客户端正是循环中最后一次成功调用的样子。这可能解释了冗余数据。

我的建议是根本不要在 select 调用中设置“writefds”。然后仅在您实际阅读时“发送”。无论如何,sendto 调用都不会阻塞很长时间。

【讨论】:

  • @selbie,对不起,它确实从服务器中删除了冗余数据,但没有解决我的问题:(
  • 事实上的情况是客户端写了一段时间然后停止,在服务器端,如果我写了一些东西,客户端发送的消息被显示,但客户端没有发生任何事情......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-29
  • 2014-08-20
相关资源
最近更新 更多