3

I'm developing a program with TCP connection, which consists of a server and multiple clients.

Server side

write(sockFd,message,strlen(message));
write(sockFd,message2,strlen(message2));

Client side

char msg[256];

bzero(msg, 256);
n = read (listenFd, msg, 255);
cout << "Msg1 " << msg << endl;

bzero(msg, 256);
n = read (listenFd, msg, 255);
cout << "Msg2 " << msg << endl;

The problem is after the server write() the two messages, the first read() on the client(s) may read all of messages from server. For example, the output is Msg 1 content-of-msg1content-of-msg2. Why it can happen?

ZZZ
  • 1,415
  • 5
  • 16
  • 29
  • 3
    TCP is a stream protocol -- there are no message boundaries. – keithmo Nov 27 '15 at 17:43
  • is there any way to make the client read the two messages on different read methods? – ZZZ Nov 27 '15 at 17:45
  • @ZZZ No. Receive it and then split up the messages manually. – deviantfan Nov 27 '15 at 17:45
  • Btw., you're probably not aware that send/recv may not process the given length completely. Check the return value and use a loop. – deviantfan Nov 27 '15 at 17:46
  • Yes, and no -- "Yes" in that you can do as @deviantfan says and parse/split the messages yourself. "No" in that there's no built-in mechanism that will do this for you. – keithmo Nov 27 '15 at 17:48
  • this may be useful: http://stackoverflow.com/questions/27527395/how-to-get-the-exact-message-from-recv-in-winsock-programming/27527668#27527668 – Giorgi Moniava Nov 27 '15 at 19:58

2 Answers2

1

TCP is a streaming protocol so data comes as a stream, this means that each read will read as much data as there is in the buffer (or as much as you requested).

So if you want to break the data down into packets or datagrams, you will need to do so with your own session based protocol. One way of doing this is prefixing the outgoing data with 4 bytes of length. This way the reader can first read the length and that way know how big the rest of the datagram is.

doron
  • 27,972
  • 12
  • 65
  • 103
  • A "session-based" protocol? – deviantfan Nov 27 '15 at 17:47
  • 2
    "This way the reader can first read the length and that way know how big the rest of the datagram is." -- being careful because even the 4 byte "length" field may be split across multiple `recv()` calls. – keithmo Nov 27 '15 at 17:50
1

It is because of stream nature of socket writes and reads. You must implement your own message distinguish technique.

Some variants are:

  • Worser: implement your own message end symbol.
  • Better: before the message send size of that message (measured in bytes). And at first read the size, then read number of bytes given by size.

And use C++11, it's 2015 year today, don't do the old C style.

For example (error checking omitted for simplicity of the example):

Server side:

// choose this type once and never change it after first release!
using message_size_t = uint64_t;

void write_message(int sockfd, const std::string & message)
{
    message_size_t message_size{ static_cast<message_size_t>(message.size()) };

    // check error here:
    write(sockfd, &message_size, sizeof(message_size));

    // and here:
    write(sockfd, message.data(), message_size);
}

// use:
write_message(sockFd, message);
write_message(sockFd, message2);

Client side:

void read_bytes_internal(int sockfd, void * where, size_t size)
{
    auto remaining = size;

    while (remaining > 0) {
        // check error here
        auto just_read = recv(sockfd, where, remaining);
        remaining -= just_read;
    }
} 

std::string read_message(int sockfd)
{
    message_size_t message_size{ 0 };
    read_bytes_internal(sockfd, &message_size, sizeof(message_size));

    std::string result{ message_size, 0 };
    read_bytes_internal(sockfd, &result[0], message_size);

    return result;
}


// use:
cout << "Msg1 " << read_message(listenFd) << endl;
cout << "Msg2 " << read_message(listenFd) << endl;

(Code may contain some small errors, I wrote it right here in stackoverflow answer window and didn't syntax-check it in IDE.)

vladon
  • 8,158
  • 2
  • 47
  • 91