无法接收使用MSG_MORE标志发送的最后一个套接字数据

时间:2011-04-29 08:33:42

标签: c sockets tcp

服务器端代码:

 dirp=opendir(path);
    if(dirp==NULL)
    {
        strcpy(err,"error:");
        strcat(err,strerror(errno));
        send(fd,err,sizeof(err),0); 
    }       
    else
    {
        printf("\nstream opened\n");
        while((dp=readdir(dirp))!= NULL)
        {

            r=send(fd,dp->d_name,100,MSG_MORE);
            if(r<0)
                perror("\nsend:");
            printf("\n%s",dp->d_name);

        }
    }

客户端:

while(recv(mainsocket,lsbuf,100,0)>0)
{
    printf("\n %s",lsbuf);
    bzero(lsbuf,sizeof(lsbuf)); 
}

服务器端正在打印标准输出上的所有文件名,但在客户端,客户端没有收到最后一个文件名,程序在此时被阻止

2 个答案:

答案 0 :(得分:3)

问题在于send系统调用。您使用MSG_MORE标志调用它意味着将跟随更多数据并发送等待更多数据而不实际发送。您应该在没有此标志的情况下发送的最后一块数据。因此,您的服务器端应如下所示:

dp = readdir(dirp);
if (dp != NULL)
{
    /* each time check whether there are more data */
    while((dp_next = readdir(dirp))!= NULL)
    {
        r = send(fd, dp->d_name, 100, MSG_MORE);
        if (r < 0) {
            perror("\nsend");
        }
        printf("\n%s",dp->d_name);
        dp = dp_next;
    }

    /* send the last or the only record */
    r = send(fd, dp->d_name, 100, 0);
    if (r < 0) {
        perror("\nsend");
    }
}

解决问题的另一个可能性是关闭close(fd)系统调用的连接。它在关闭连接之前发送缓冲区中的所有数据。这是一个不太干净但更简单的解决方案。

答案 1 :(得分:1)

您的客户在 lsbuf之前打印换行符,因此自上一个换行符以来的所有内容都会在输出缓冲区中丢失。

四种解决方案:

  • 使用printf("%s\n", lsbuf);代替..."\n %s"...
  • 使用puts(lsbuf);,效果相同但稍微合适
  • 在客户端循环后使用fflush(stdout)来刷新输出缓冲区
  • 使用无缓冲输出,有关详细信息,请参阅setvbuf()

请注意,此问题似乎与网络无关(虽然我将MSG_MORE替换为0),但这只是输出缓冲的问题。


在旁注中,我强烈建议发送strlen(dp->d_name) + 1个字节而不是100个字节。这样,您将不会发送超过必要的字节数,另一方面,如果您的目录条目恰好大于100个字节,则不会截断输出。

此外,您的客户端和服务器都不会检查send() / recv()是否返回0,这意味着远程端已关闭连接。