【问题标题】:TCP client failed to send string to serverTCP 客户端无法向服务器发送字符串
【发布时间】:2014-03-10 07:34:17
【问题描述】:

我正在编写 TCP 服务器客户端。我使用单独的send 系统调用分别发送三个字符串。 但是接收端我只得到一个字符串,这是我发送的第一个字符串。剩下的两个字符串错过了。

下面我给出了我的服务器客户端程序的一部分。

client.c

char *info = "infolog";
char *size = "filesize";
char *end = "fileend";
send(client, info, strlen(info)+1, 0);
send(client, size, strlen(size)+1, 0);
send(client, end, strlen(end)+1, 0);

服务器.c

while ((read_size = recv(client, msg, sizeof(msg), 0))) {
    printf("Data: %s\n", msg);
    memset(msg, 0, sizeof(msg));
}

实际输出:

Data: infolog

预期输出

Data: infolog
Data: filesize
Data: fileend

谢谢。

【问题讨论】:

  • 尝试打印出read_size。您很可能同时收到了这三条消息。
  • @Mike 你是对的。我收到所有字符串的strlen。为什么服务器不单独接收?
  • 请参阅下面的 Basile 回答。 TCP 是基于流的,因此您可能会收到比已经发送的更多或更少的输出,具体取决于网络条件、缓冲等。
  • “比已经发送的输出更多” - 大声笑。我的意思是在发送一个小的send() 后,输出比您预期的要多(尤其是当您知道它们立即被其他send() 调用时)

标签: c linux tcp send


【解决方案1】:

TCP不是消息协议,而是字节流协议。

三个send-s 可以是recv-ed 作为单个输入(或其他东西,例如两个或五个recv 等......)

应用程序应分析输入并对其进行缓冲,以便能够将其拼接成有意义的消息。

传输可能会拆分或合并消息,例如中间路由器可以并且将拆分或合并“数据包”。

在实践中,您最好对您的消息有一些好的约定。要么决定每条消息是例如换行符终止,或者决定它以一些给出其大小的标题开头。

查看HTTPSMTPIMAPSCGIONC/XDR(记录在RFC5531)作为具体示例。并很好地记录您的协议(最低限度,在一些家庭作业玩具项目的长描述性 cmets 中,更严重的是,在单独的公共文档中)。

【讨论】:

    【解决方案2】:

    尝试打印出read_size。您可能已经收到了所有消息。

    由于Nagle's Algorithm,发件人可能将您的三个send() 调用分批处理,并向服务器发送了一个数据包。虽然您可以禁用 Nagle 的算法,但我认为在这种情况下这不是一个好主意。您的服务器需要能够处理部分数据的接收,并处理接收比预期更多的数据。

    您可能想考虑为您的消息使用上层协议,例如Google Protocol Buffers。看看techniques 页面,他们在其中描述了他们可能如何做到这一点:建立一个协议缓冲区,并在写入缓冲区本身之前将其长度写入流。这样接收方就可以读取长度,然后确定在获得完整消息之前需要读取多少字节。

    【讨论】:

    • 有什么方法可以满足我的需求吗?我已经在 TCP 中实现了大部分代码。所以改变协议是不可能的。
    • @sujin:不,不是真的。您必须设计您的协议和应用程序来管理字节流,TCP 中没有“应用程序消息”的概念。你的代码应该可以承受。
    • 事实上,如果你不处理这个问题,你就没有正确地实现你的代码:你犯了一个巨大的设计错误。
    • @sujin 不一定。如果实现基于 UDP 的协议,则必须自己实现可靠性。
    猜你喜欢
    • 1970-01-01
    • 2021-02-21
    • 1970-01-01
    • 2015-12-01
    • 2019-07-24
    • 2017-10-11
    • 2012-10-25
    • 2017-07-10
    • 2011-06-25
    相关资源
    最近更新 更多