0

System include some clients and server. Client send message to server have 3 types of message:

  • Connection setup: User type command-line: remote-chat <IP addr server>: <port addr server> <IP address client>: <port addr client>, a link TCP connection will be established between the client and server chat. After the TCP connection is set, the client sends the connection setup information, including some fields:
    • The message identifier: is a 32-bit integer. With Connection setup message, this field equal to 0.
    • Field IP address of client 2 (client 1 call), Port address of client 2.

Server receive this message. Then create a connection to client 2.

  • Data exchange: used to exchange data between client and server. Include some fields:
    • The message identifier: is a 32-bit integer. With Data exchange message this field = 1
    • The data length: an integer indicating the length of the text message.
    • The data text field: contains text messages to exchange.

When receiving data sent from client 1, chat server transfer text messages from client 1 to client 2 (client 2 also using data exchange message).

So my question is: how do I send the message with some field? I already know send string by function send(). Here I have to send message Connection Setup or Data exchange with some field then I whether used pack in client side then unpack in server side or not? Please give me some solution for this problem?

I think use:

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;
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278

3 Answers3

1

You should try it yourself, its very educational. Some short advice, though:

  1. Always put the message_ID first in the message, so you can recognize incoming messages by reading the first 4 bytes.
  2. At the sending end, encode the fields of the structure in a char *buffer and send it with send(fd, buf, mlen, 0), e.g.,. (int *) buffer = htonl(hello_msg.message_ID); mlen = mlen + sizeof(hello_msg.message_ID);
  3. At the receiving end do the revers. hello_msg.message_ID = ntohl(*(int *)buffer);
  4. For the rest of the fields, keep count of the offset in the send/receive buffer.

EDIT For a c-language example you might look at e.g. https://stackoverflow.com/questions/5759043/sending-message-over-tcp-ip-using-sockets

Community
  • 1
  • 1
thuovila
  • 1,960
  • 13
  • 21
  • You mean all field we will send in one buffer? Then encode on server side back to some field client sent? Thanks for your advice. I will try myself. – Hùng Nguyễn May 30 '13 at 07:41
  • Yes, I think you understood correctly. Encode all fields into one buffer on sending side. Decode into same struct on receiving side. The link has a short example. – thuovila May 30 '13 at 07:43
1

Use serialization for your structures. And be aware never send pointers, but fully serialized data(strings). For more information read https://stackoverflow.com/a/1654822/2294017 and Serialize and send a data structure using Boost?. Also http://www.ocoudert.com/blog/2011/07/09/a-practical-guide-to-c-serialization/ can be handy if you need to dive deeper.

Community
  • 1
  • 1
  • That is some good advice, but the links are for c++. The OP tagged the post c. – thuovila May 30 '13 at 07:14
  • Perhaps it is better to use JSON right away, unless there are strong requirements against it. Using JSON makes things easier if you ever need to interface with peers written in other languages. – epx Feb 03 '14 at 03:02
-1

Maybe you can try to send an identifier for the kind of message and then send the struct with a len of sizeof(your_struct), and read it on the other side the same way.

for exemple:

server side:

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

and then on the client side:

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));
Alexis
  • 2,149
  • 2
  • 25
  • 39
  • 1
    This is not a good idea. The solution ignores structure padding and data type endianness. – thuovila May 30 '13 at 07:13
  • you can use #pragma pack or something like that, no use to go into to complicate thing or serialisation if the op is new with all this stuff – Alexis May 30 '13 at 07:16
  • I agree pack might solve the padding problem in most cases. That still leaves endianness. – thuovila May 30 '13 at 07:20
  • 1
    Whatever you use you have to use at both ends. Ideally both ends must use the same binary object file, otherwise they should use the same (a) hardware (b) compiler (c) compiler version (d) compiler options (e) #pragmas (f) ... It's a poor technique. The idea is to define the *wire protocol* and then write the code you need to read and write it. – user207421 May 30 '13 at 07:25
  • You mean use pack then unpack server side? Then all fiedl will be packed into one buffer then unpack this back some field in server side. I think so too, but have another method dont use pack and unpack? – Hùng Nguyễn May 30 '13 at 07:37