使用套接字通过 Tcp/IP 发送消息 [英] Sending Message Over Tcp/IP using Sockets

查看:40
本文介绍了使用套接字通过 Tcp/IP 发送消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在客户端/服务器之间发送数据,数据看起来像

I am trying to send data between a client/Server, the data looks like

typedef Struct Message 
  { int id;
    int message_length;
     char* message_str;
    }message;

我试图在客户端和服务器之间WriteRead这条消息,不断更新这个结构中的元素.我听说 Writev 可以解决问题.我想发送一个向服务器发送消息,然后服务器取出元素并将这些元素用作条件来执行正确的方法?

I am trying to Write and Read this message between a client and server constantly updating the elements in this struct. I have heard Writev may do the trick. i want to send a message to the server and then the server pulls out the elements and uses those elements as conditionals to execute the proper method?

推荐答案

假设您想自己进行序列化而不是使用 Google Protocol Buffers 或某些库来处理它,我建议您编写一对函数,例如这个:

Assuming you want to do the serialization yourself and not use Google Protocol Buffers or some library to handle it for you, I'd suggest writing a pair of functions like this:

// Serializes (msg) into a flat array of bytes, and returns the number of bytes written
// Note that (outBuf) must be big enough to hold any Message you might have, or there will
// be a buffer overrun!  Modifying this function to check for that problem and
// error out instead is left as an exercise for the reader.
int SerializeMessage(const struct Message & msg, char * outBuf)
{
   char * outPtr = outBuf;

   int32_t sendID = htonl(msg.id);   // htonl will make sure it gets sent in big-endian form
   memcpy(outPtr, &sendID, sizeof(sendID));
   outPtr += sizeof(sendID);

   int32_t sendLen = htonl(msg.message_length);
   memcpy(outPtr, &sendLen, sizeof(sendLen));
   outPtr += sizeof(sendLen);

   memcpy(outPtr, msg.message_str, msg.message_length);  // I'm assuming message_length=strlen(message_str)+1 here
   outPtr += msg.message_length;

   return (outPtr-outBuf);
}

// Deserializes a flat array of bytes back into a Message object.  Returns 0 on success, or -1 on failure.
int DeserializeMessage(const char * inBuf, int numBytes, struct Message & msg)
{
   const char * inPtr = inBuf;

   if (numBytes < sizeof(int32_t)) return -1;  // buffer was too short!
   int32_t recvID = ntohl(*((int32_t *)inPtr));
   inPtr += sizeof(int32_t);
   numBytes -= sizeof(int32_t);
   msg.id = recvID;

   if (numBytes < sizeof(int32_t)) return -1;   // buffer was too short!
   int32_t recvLen = ntohl(*((int32_t *)inPtr));
   inPtr += sizeof(int32_t);
   numBytes -= sizeof(int32_t);
   msg.message_length = recvLen;       if (msg.message_length > 1024) return -1;  /* Sanity check, just in case something got munged we don't want to allocate a giant array */

   msg.message_str = new char[msg.message_length];
   memcpy(msg.message_str, inPtr, numBytes);
   return 0;
}

使用这些函数,您现在可以将 Message 转换为简单的字符数组,然后随意返回.所以现在您要做的就是通过 TCP 连接发送字符数组,在远端接收它,然后将数组反序列化回那里的 Message 结构.

With these functions, you are now able to convert a Message into a simple char-array and back at will. So now all you have to do is send the char-array over the TCP connection, receive it at the far end, and then Deserialize the array back into a Message struct there.

与此有关的一个问题是您的字符数组将是可变长度的(由于存在长度不同的字符串),因此您的接收器将需要一些简单的方法来了解在调用 DeserializeMessage 之前要接收多少字节() 在数组上.

One wrinkle with this is that your char arrays will be variable-length (due to the presence of a string which can be different lengths), so your receiver will need some easy way to know how many bytes to receive before calling DeserializeMessage() on the array.

一种简单的处理方法是在发送字符数组之前始终先发送一个 4 字节整数.4 字节整数应始终是即将到来的数组的大小,以字节为单位.(确保在发送之前先通过 htonl() 将整数转换为 big-endian,然后在使用前通过 htonl() 在接收方将其转换回 native-endian).

An easy way to handle that is to always send a 4-byte integer first, before sending the char-array. The 4-byte integer should always be the size of the upcoming array, in bytes. (Be sure to convert the integer to big-endian first, via htonl(), before sending it, and convert it back to native-endian on the receiver via htonl() before using it).

这篇关于使用套接字通过 Tcp/IP 发送消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆