分别通过TCP套接字发送和接收字符串

时间:2012-12-01 05:29:56

标签: c sockets tcp

我有一个TCP服务器和客户端,带有已建立的套接字。假设我有以下情况:

SERVER:

char *fn = "John";
char *ln = "Doe";

char buffer[512];

strcpy(buffer, fn);
send(*socket, buffer, strlen(buffer), 0);
strcpy(buffer, ln);
send(*socket, buffer, strlen(buffer), 0);

客户端:

char *fn;
char *ln;

char buffer[512];

bytes = recv(*socket, buffer, sizeof(buffer), 0);
buffer[bytes] = '\0';
strcpy(fn, buffer);

bytes = recv(*socket, buffer, sizeof(buffer), 0);
buffer[bytes] = '\0';
strcpy(ln, buffer);

printf("%s", fn); 
printf("%s", ln);

预期结果: 我想分别收到每个字符串(因为我将它们保存在不同的变量中),而第一个recv()获取fn“John”和ln“Doe”连接“JohnDoe”,程序卡在第二个recv上()...因为我已经完成了发送。

我尝试了以下内容:   - 将\ 0添加到fn和ln字符串中,如下所示:

char *fn = "John\0";
char *ln = "Doe\0";

但问题仍然存在。

我可以施加某种条件,以便单独收到每个字符串吗?

编辑添加更多问题:

1)为什么在某些情况下它实际上是单独发送它们,而其他实际发送它们呢?

2)我应该发送()和recv()吗?在我的代码的其他一些部分,它似乎是自我调节,只在正确的时间接收正确的字符串,而我不必检查。这样做了吗?

3)关于发送一个标题我将要发送的字符串的长度,如何解析传入的字符串以知道在哪里拆分?任何例子都会很棒。

4)我肯定会检查我是否收到比缓冲区大的东西,谢谢你的指点。

编辑2:

5)因为我总是把东西放在大小为512的缓冲区字符数组中。即使我发送1个字母的字符串,也不应该每个发送操作都占用缓冲区的全部大小吗?这令人困惑。我有“John”,但我把它放在一个大小为512的数组并发送它,不应该填满发送缓冲区,所以recv()函数通过拉动整个数组来清空网络缓冲区512?

4 个答案:

答案 0 :(得分:10)

首先,当客户端调用recv(*socket, buffer, sizeof(buffer), 0);时,它将从网络接收最多 sizeof(缓冲区)字符(此处为512)。这来自网络缓冲区,与服务器上调用send的次数无关。 recv不查找\0或任何其他字符 - 它是来自网络缓冲区的二进制拉。它将读取整个网络缓冲区或sizeof(buffer)个字符。

您需要检查第一个recv,看它是否同时包含名字和姓氏,并妥善处理。

您可以通过让服务器将字符串的长度作为流的前几个字节(“标题”)发送,或者通过扫描接收的数据来查看是否有两个字符串来实现。

每当你调用recv时,你真的需要执行检查 - 如果字符串长度超过512字节怎么办?然后你需要多次调用recv来获取字符串。如果你得到第一个字符串,只有第二个字符串的一半怎么办?通常这两种情况只会在处理大量数据时发生,但我之前看到它发生在我自己的代码中,所以最好在recv上加入好的检查,即使处理这样的小字符串也是如此。如果你在早期练习良好的编码策略,就不会有太多令人头痛的问题。

答案 1 :(得分:2)

正确的做法是用标题包含发送的数据。因此,您将传递消息的大小,包括消息的大小,然后在另一方面,您可以确定消息的长度。

约翰是4个字符,所以你有长度,像“0004John”那样你会知道什么时候停止阅读。您可能还想在标题中添加命令,这很常见。例如,名字可能是1,第二名称是2;

例如,“01004JOHN”将在缓冲区中设置并发送。

要执行此操作,请将项添加到缓冲区,然后按添加的值的大小增加缓冲区中的插入点。您可以使用它将许多部件添加到缓冲区。 *请确保不要超出缓冲区的大小。

记住这些给出的例子不正确,因为你没有传递数字的字符串表示,只是数字,所以它将是一个long int 1,long int 4然后是chars,或unicode,无论如何,4字符。

答案 2 :(得分:2)

TCP是面向流的,而不是面向数据报的。如果是后者,你的东西会很好用。您有以下选择:

  • 使用SCTP
  • 如果能够承受失去的可靠性,请使用UDP
  • 以您可以使用的方式分隔字符串,方法是预先设置长度标记,或者添加NUL字节以终止每个字符串。

对于后者,你只需send(*socket, buffer, strlen(buffer)+1, 0);来包含NUL,但发件人会重复recv()并找到一个字符串终结符,直到找到2个字符串为止

请注意,您应该注意strcpy():只有在您完全确定要写入的字符串正常时才使用它。

您的接收器确实

bytes = recv(*socket, buffer, sizeof(buffer), 0);
buffer[bytes] = '\0';

这很糟糕,因为如果缓冲区已满,那么bytes == sizeof(buffer)(这可能发生在更复杂的情况下),buffer[bytes] = '\0'写入缓冲区之外。所以使用

bytes = recv(*socket, buffer, sizeof(buffer) - 1, 0);

你可以高兴地做到

buffer[bytes] = '\0';

答案 3 :(得分:0)

而不是sizeof(缓冲区)使用strlen(fn);因此它只传输确切的字节数量。如果你需要使用null终止符,请使用strlen(fn)+1,但不要忘记将null终结符与strcat()连接起来

如果您发送所有缓冲区大小而不使用memset进行清理,那么您也会有垃圾,所以要小心..