Отправка сообщения по TCP / IP с использованием сокетов - PullRequest
0 голосов
/ 22 апреля 2011

Я пытаюсь отправить данные между клиентом / сервером, данные выглядят как

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

Я пытаюсь Write и Read это сообщение между клиентом и сервером постоянно обновлять элементы в этой структуре. Я слышал, Writev может добиться цели. я хочу отправить сообщение на сервер, а затем сервер извлекает элементы и использует эти элементы как условные для выполнения надлежащего метода?

Ответы [ 3 ]

1 голос
/ 02 октября 2012

Предполагая, что вы хотите выполнить сериализацию самостоятельно и не использовать буферы протокола Google или какую-либо библиотеку для ее обработки, я бы предложил написать пару функций, подобных этой:

// 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;
}

С помощью этих функций вы теперь можете конвертировать Сообщение в простой массив символов и обратно по желанию. Поэтому теперь все, что вам нужно сделать, это отправить массив char через TCP-соединение, получить его на дальнем конце и затем десериализовать массив обратно в структуру Message.

Один недостаток в том, что массивы символов будут переменной длины (из-за наличия строки, которая может быть разной длины), поэтому вашему получателю понадобится простой способ узнать, сколько байтов получить до вызова DeserializeMessage. () в массиве.

Простой способ справиться с этим - всегда отправлять 4-байтовое целое число перед отправкой массива char. 4-байтовое целое число всегда должно быть размером предстоящего массива в байтах. (Обязательно сначала преобразуйте целое число в big-endian с помощью htonl (), прежде чем отправлять его, и преобразуйте его обратно в native-endian на приемнике с помощью htonl () перед его использованием).

1 голос
/ 23 апреля 2011

Хорошо, я попробую.Я собираюсь предположить, что у вас есть объект «сообщения» на отправляющей стороне, и вам нужно как-то отправить его на другой компьютер и восстановить там данные, чтобы вы могли выполнить некоторые вычисления на нем.Часть, о которой вы можете не знать, - как кодировать данные для связи, а затем декодировать их на принимающей стороне, чтобы восстановить информацию.Упрощенный подход простой записи байтов, содержащихся в объекте «сообщение» (т. Е. Запись (fd, msg, sizeof (* msg), где «msg» - указатель на объект типа «сообщение»), не будет работать, потому чтов итоге вы отправите значение виртуального адреса в памяти одной машины на другую машину, и на принимающей стороне вы мало что можете сделать с этим. Поэтому проблема состоит в том, чтобы разработать способ передачи двух целых чисел и символаСтруны связаны таким образом, что вы можете выловить их обратно на другом конце. Есть, конечно, много способов сделать это. Описывает ли это то, что вы пытаетесь сделать?

0 голосов
/ 02 октября 2012

Вы можете отправлять структуры через сокет, но вы должны сериализовать их перед отправкой структуры с использованием ускоренной сериализации.

Вот пример кода:

    #include<iostream>
    #include<unistd.h>
    #include<cstring>
    #include <sstream> 

    #include <boost/archive/text_oarchive.hpp>
    #include <boost/archive/text_iarchive.hpp>

    using namespace std;

    typedef struct {
        public:
            int id;
            int message_length;
            string message_str;
        private:
        friend class boost::serialization::access; 
        template <typename Archive> 
        void serialize(Archive &ar, const unsigned int vern) 
        { 
            ar & id; 
            ar & message_length;
            ar & message_str;
        }
    } Message;

    int main()
    {
        Message newMsg;
        newMsg.id = 7;
        newMsg.message_length = 14;
        newMsg.message_str="Hi ya Whats up";

        std::stringstream strData;
        boost::archive::text_oarchive oa(strData);
        oa << newMsg;
        char *serObj = (char*) strData.str().c_str();

        cout << "Serialized Data ::: " << serObj << "Len ::: " << strlen(serObj) << "\n";
        /* Send serObj thru Sockets */


        /* recv serObj from socket & deserialize it */
        std::stringstream rcvdObj(serObj);
        Message deserObj;
        boost::archive::text_iarchive ia(rcvdObj);
        ia >> deserObj;
        cout<<"id ::: "<<deserObj.id<<"\n";
        cout<<"len ::: "<<deserObj.message_length<<"\n";
        cout<<"str ::: "<<deserObj.message_str<<"\n";
    }

вы можете скомпилировать программу по

g ++ -o serial boost.cpp /usr/local/lib/libboost_serialization.a

на вашем компьютере должен быть статически скомпилирован libboost_serialization.a.

Будет полезно сохранить блокировку сокетов, и вам нужно будет разработать эти структуры для чтения из буфера recv.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...