【问题标题】:Send() message include some field in TCP socket (C Linux)Send() 消息包含 TCP 套接字中的某些字段(C Linux)
【发布时间】:2013-05-25 15:24:35
【问题描述】:

系统包括一些客户端和服务器。客户端向服务器发送消息有 3 种类型的消息:

  • 连接设置:用户类型命令行:远程聊天<IP addr server>:<port addr server><IP address client>:<port addr client>,客户端和服务器聊天之间将建立一个链接TCP连接。 TCP连接建立后,客户端发送连接建立信息,包括一些字段:
    • 消息标识符:是一个 32 位整数。对于连接设置消息,此字段等于 0。
    • 客户端 2 的字段 IP 地址(客户端 1 调用),客户端 2 的端口地址。

服务器收到此消息。然后创建到客户端 2 的连接。

  • 数据交换:用于客户端和服务器之间的数据交换。包括一些字段:
    • 消息标识符:是一个 32 位整数。对于数据交换消息,此字段 = 1
    • 数据长度:表示短信长度的整数。
    • 数据文本字段:包含要交换的文本消息。

聊天服务器收到客户端1发来的数据时,会传输短信 从客户端 1 到客户端 2(客户端 2 也使用数据交换消息)。

所以我的问题是:如何发送带有某些字段的消息?我已经知道通过函数 send() 发送字符串。在这里我必须发送消息连接设置或与某些字段进行数据交换然后我是否在客户端使用包然后在服务器端解包?请给我一些解决这个问题的方法?

我认为使用:

typedef struct _ConnectionSetup_Message
{
    int  message_ID;    // 0 ConnectionSetup message
    unsigned int Port;
    unsigned shor IP;
} HELLO_Message;

typedef struct _DataExchange_Message
{
    int  message_Length;
    int  message_ID;    // 1 for DataExchange message
    char *text;
} DataExchange_Message;

【问题讨论】:

  • send() 不发送字符串。检查你的假设。

标签: c linux sockets tcp


【解决方案1】:

为您的结构使用序列化。并注意永远不要发送指针,而是完全序列化的数据(字符串)。 更多信息请阅读https://stackoverflow.com/a/1654822/2294017Serialize and send a data structure using Boost?。 如果您需要深入了解,http://www.ocoudert.com/blog/2011/07/09/a-practical-guide-to-c-serialization/ 也很方便。

【讨论】:

  • 这是一些很好的建议,但这些链接适用于 c++。 OP 将帖子标记为 c。
  • 也许最好马上使用 JSON,除非有强烈的要求。如果您需要与用其他语言编写的对等方进行交互,使用 JSON 可以让事情变得更容易。
【解决方案2】:

你应该自己尝试一下,它很有教育意义。不过,一些简短的建议:

  1. 始终将 message_ID 放在消息的最前面,这样您就可以通过读取前 4 个字节来识别传入的消息。
  2. 在发送端,将结构的字段编码到 char *buffer 中,并使用 send(fd, buf, mlen, 0) 发送,例如,。 (int *) 缓冲区 = htonl(hello_msg.message_ID); mlen = mlen + sizeof(hello_msg.message_ID);
  3. 在接收端进行反转。 hello_msg.message_ID = ntohl(*(int *)buffer);
  4. 对于其余字段,保持发送/接收缓冲区中的偏移计数。

EDIT 对于 c 语言示例,您可以查看例如https://stackoverflow.com/questions/5759043/sending-message-over-tcp-ip-using-sockets

【讨论】:

  • 您的意思是我们将在一个缓冲区中发送的所有字段?然后在服务器端编码回一些发送的现场客户端?谢谢你的建议。我自己试试。
  • 是的,我认为您理解正确。将所有字段编码到发送端的一个缓冲区中。在接收端解码成相同的结构。该链接有一个简短的示例。
【解决方案3】:

也许您可以尝试发送消息类型的标识符,然后发送长度为 sizeof(your_struct) 的结构,并以相同的方式在另一端读取它。

例如:

服务器端:

 write(socket, &flag, sizeof(flag));
 write(socket, &your_struct, sizeof(DataExchange_Message));

然后在客户端:

read(socket, &flag, sizeof(flag));

//and according to the flag you can do what you want because you know what you are going to receive 
read(socket, &your_struct, sizeof(your_struct));

【讨论】:

  • 这不是一个好主意。该解决方案忽略了结构填充和数据类型字节序。
  • 你可以使用 #pragma pack 或类似的东西,如果操作是新的所有这些东西,就没有必要让事情复杂化或序列化
  • 我同意 pack 在大多数情况下可以解决填充问题。这仍然留下字节序。
  • 无论你使用什么,你都必须在两端使用。理想情况下,两端必须使用相同的二进制目标文件,否则它们应该使用相同的 (a) 硬件 (b) 编译器 (c) 编译器版本 (d) 编译器选项 (e) #pragmas (f) ...这是一种糟糕的技术.思路是定义wire协议,然后编写自己需要读写的代码。
  • 你的意思是先打包然后解压服务器端?然后所有字段将被打包到一个缓冲区中,然后在服务器端将其解包回某个字段。我也这么认为,但是有另一种方法不使用打包和解包吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-07
  • 2019-04-26
  • 1970-01-01
  • 1970-01-01
  • 2014-03-02
  • 2017-11-08
  • 1970-01-01
相关资源
最近更新 更多