2

I am facing a big issue in TCP client application return in c#. Normal case it's working fine but in some case server send simultaneous response to a particular client, so this case all the simultaneous response are received as a single message in client side.So this case client failed to identify individual message. So such a case my client application failed to handle a particular activity. Is it possible to read as individual message in client side ?. So for solving this issue, I have some choices but i don't know if it is correct way.

1- Using a fixed length buffer in client side(But my message are variable length).

2- Add a delimiter to each response message.

If any one know the solution for resolving such problem please help me.

Hope
  • 1,252
  • 4
  • 17
  • 35
  • I'd go for the delimiter, indicating the size of each message as the first few bytes could work as well though – BlackBear Sep 10 '12 at 12:53
  • But the received stream having multiple message know. So such a case I want to handle all message. I cannot avoid a single message in that. So that case what i do.... Thank you for your valuable replay. – Hope Sep 10 '12 at 12:59

3 Answers3

5

TCP is stream based, you get a stream of data from a client to server. You need to "deserialize" what you're expecting from the stream, if you can't build an application protocol that ensures each message sent is separately (which usually isn't a wise idea anyway with TCP).

So, you need to send with each message something that allows you to differentiate what the data is. This is often done with tag or type data at the start of each message. Sometimes a byte will do (depending on how many different message types you have). You then read that byte from the stream and decide what to deserialize next. e.g. if you want to send a string, you might serialize '1', then the string. If you want to send a date/time, you might serialize '2' then the DateTime. On the server, if both of those objects got sent about the same time, you could simply deserialize the byte, and if it was '1', deserialize a string, then continue deserializing: get the next byte, and if it's a '2', deserialize a DateTime.

It's important to remember that TCP is a stream-based protocol, not a message-based protocol. Message-based needs to be implemented at the application level--e.g. something like the above.

And by "serialize" and "deserialize" I mean the typical built-in serializers and deserializers as described in Serializing Objects in the .NET documentation. The same would hold true for JSON serializers included in libraries like JSON.NET or the built-in DataContractJsonSerializer and JavaScriptSerializer.

Peter Ritchie
  • 35,463
  • 9
  • 80
  • 98
  • It's also helps to make application message length explicit - say, include it in a fixed-length header. That way it's easier on the receiver side to know how much to expect. Other options are delimited messages, and self-describing formats like XML. – Nikolai Fetissov Sep 10 '12 at 13:26
  • So I think this is one of the best solution. I want to look into this... Thanks Peter.. – Hope Sep 10 '12 at 13:27
  • @NikolaiNFetissov Well, if you're using one of the built-in serializers, a specific message length is not needed. Deserializing a string will only deserialize enough data to get the string--the same with DateTime. – Peter Ritchie Sep 10 '12 at 13:27
  • Yes, this is true if you stay within same language like C#. As soon as you more beyond that and need to talk to something else, you'd have to worry about this sort of things. – Nikolai Fetissov Sep 10 '12 at 13:32
  • @NikolaiNFetissov Well, it really comes down to delineating the data. That *could* be by message size; but it could be by the type of data. e.g. deserializes stick type data in the stream so it knows what it is deserializing and how much data is needs to deserialize. If the OP is using JSON, that works out to the same thing. JSON data is deliniated with characters like '{' and '}', so it's easy to see how much data is to be read per message without having to restrict to message size. – Peter Ritchie Sep 10 '12 at 13:35
  • @PeterRitchie: A string is not fixed length and it doesn't have a null terminator like in C. so how would you deserialize it without using a delimiter or a length header? – jgauffin Sep 10 '12 at 13:41
  • @jgauffin He's using JSON so it doesn't matter. But, if he was using the built-in serialization the serializer knows now much data to deserialize because it serialized length data when it serialized a string--you just need to tell it to deserialize a string, if you don't know that implicitly (because you have only one message that you're expecting to receive) then you need to include type data to differentiate the message type (i.e. it's contents). – Peter Ritchie Sep 10 '12 at 13:45
  • @PeterRitchie: I was referring to your answer: `You then read that byte from the stream and decide what to deserialize next. e.g. if you want to send a string, you might serialize '1', then the string` – jgauffin Sep 10 '12 at 13:46
  • @Peter, yes, all true. I am talking about how to implement those serializers/de-serializers. – Nikolai Fetissov Sep 10 '12 at 13:46
  • @jgauffin Have you serialized strings? `while(!EndOfStream) {var b = stream.ReadByte(); if (b==1) {text = (String)binaryFormatter.Deserialize(stream);} if (b==2) {dateTime = (DateTime)binaryFormatter.Deserialize(stream);}}` the serializer deals with the deliminators for you, you don't have to. – Peter Ritchie Sep 10 '12 at 14:01
  • If you use the binary formatter, yes.. But a formatter wasn't mentioned in the question. Just a general question about how to deal with multiple messages. If you're answer is specific for the binary formatter, then say so. It you take the `DataContractJsonSerializer` or `JavascriptSerializer` they do not specify their sizes (or the xml serializer etc etc). – jgauffin Sep 10 '12 at 14:03
  • In the context of "serialization" in .NET, it's either very common that you're talking about .NET serializers and formatters. See "Serializing Objects": http://msdn.microsoft.com/en-us/library/7ay27kt9(VS.71).aspx But, yes, I could clarify that. – Peter Ritchie Sep 10 '12 at 14:06
  • I'm well aware of how serialization works (read my article in my answer). Go ahead and try to use a `BinaryFormatter` on a half message (if TCP have breaken up the message into two packets). It will bite you. – jgauffin Sep 10 '12 at 14:10
  • In other words: Since TCP is stream based, no serializer in the world would work unless you make sure that the entire serialized message has arrived. You can do that by using a binary header or a message delimiter, where I recommend the first approach since it's easier as you don't have to make sure that the serialized data do not contain the delimiter. – jgauffin Sep 10 '12 at 14:14
  • @jgauffin Do you mean truncation of data? If all the data isn't received yet, the stream will block the serializer until the data arrives--much the same way as sending the size and waiting for x number of bytes would. Otherwise every application message sent over TCP would have a size at the start, and I've *never* had one that did that. e.g. I deal with many off-the-shelf TCP devices that only send a message type and no length in their application-specific messages. – Peter Ritchie Sep 10 '12 at 14:56
  • @PeterRitchie: oops. Just wrote a small sample to try it out. You are correct. sorry. Guess I've been using async too much (i.e. having to build up the entire message or try deserialize and catch the exception on every receive = always do the first option) – jgauffin Sep 10 '12 at 15:11
0

Just make sure that each message has its length as first few bytes, this way you can split the whole into single messages.

For example, suppose that you receive this 20 bytes message from your server:

                                       (1)                                     (2)
0   1   2   3   4   5   6   7   8   9   0   1   2   3   4   5   6   7   8   9   0

+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 2 | 4 | 6 | 1 | 5 | 3 | 3 | 2 | 6 | 3 | 4 | 1 | 6 | 2 | 3 | 5 | 3 | 0 | 4 | 6 |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  ^           ^       ^               ^               ^           ^
  • The first byte says that the first message has 2 bytes of data, so you can retrieve that message as bytes 1 and 2.
  • Next you read byte 3 which tells you that the second message has only 1 byte of additional data (byte 4).
  • The third and the fourth message have 3 bytes of data (as bytes 5 and 9 indicate), then there's a 2 bytes message and a 3 bytes one.
Community
  • 1
  • 1
BlackBear
  • 22,411
  • 10
  • 48
  • 86
  • How would he differentiate between each message? Assuming each message needs to be processed independently? – Peter Ritchie Sep 10 '12 at 13:40
  • @PeterRitchie: He should use another few bytes to indicate what kind of message it is, but he already does it in some way ("Normal case it's working fine") – BlackBear Sep 10 '12 at 13:42
  • If you already know what the message type is, why would you care what the length is? If it's fixed length you already know that by the type. If you use built-in serializers, it *does* put length data in for each object is serializes, you just need to know what types of objects you're deserializing and it does all the rest. There's no need to add more. – Peter Ritchie Sep 10 '12 at 13:46
  • @PeterRitchie: I don't know how he builds the messages but yours might be an option. His problem is when many messages are sent as a bigger one and mine was just an option to split them. I see your point though, using length is more verbose – BlackBear Sep 10 '12 at 13:50
-1

Using a fixed length header which contains at least the body length is the easiest way to go. Then depending on the body you might need additional information (like the type name if you want to use something like JSON to serialize/deserialize the actual message).

If you don't want to take care of everything yourself you could use a networking library like mine. Scroll down to the end of the article to see a JSON RPC sample implementation. You can take most of that to get a JSON based communication channel.

jgauffin
  • 99,844
  • 45
  • 235
  • 372