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

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

服务器:

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?

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

您需要检查第一个recv以查看它是否同时具有名字和姓氏并进行适当处理。

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

每次调用recv时都需要执行检查 – 如果字符串超过512字节会怎样? 然后你需要多次调用recv获取字符串。 如果你得到第一个字符串,只有第二个字符串的一半怎么办? 通常这两种情况只会在处理大量数据时发生,但我之前已经看到它发生在我自己的代码中,因此即使在处理像这样的小字符串时也最好对recv进行良好的检查。 如果你在早期练习良好的编码策略,你将不会有太多的麻烦。

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

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

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

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

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

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

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

如果你发送所有的缓冲区大小而不用memset清理你也会有垃圾,所以要小心..