Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# NetworkStream - distinguish closed socket from 0-byte array on Read

[SOLVED, the question is based on incorrect assumptions]

While working with TCP I came across an issue with NetworkStream.Read returning value 0 in two separate cases, which I have trouble distinguishing.

A bit of background - I have a working client-server solution communicating via TCP using length-prefixed messages. However, since most of the communication (apart from some initial messages exchange) happens from Client to Server, the Server doesn't have a good way to know whether a Client is still connected or not. One way to find this out is to send something to the Client from time to time, and that is what I decided to do.

I know that I can add a dedicated "ping" message to my protocol, and simply ignore it in the Client, but I was also testing for other possibilities. One thing I tried was to send an empty byte array to the Client like so:

networkStream.Write(new byte[0], 0, 0);

All looks good, it seems to be sending a TCP packet with no data in it... however! My client code does expect data from the Server from time to time, so it has a thread that blocks on networkStream.Read, like so:

int bytesRead = networkStream.Read(buffer, 0, 4);
if (bytesRead == 0)
    break;

According to the docs, Socket.Read (or NetworkStream.Read) returns 0 if the other end closes the connection. This is true, but in my case, after sending the empty byte array, Read(...) also returns 0.

So far I was unable to distinguish those two situations. Socket.Connected checked after Read is true in both cases (connection closed and the empty byte array). Is there any other way to handle this?

Again, I do know that sending this empty array is almost the same as adding a new type of message for that purpose. I am not asking for a solution here... just wanted to know if .NET's Socket can distinguish between an empty byte array and connection closing.

EDIT: I am sorry for bothering everyone with a question, that in the end was based on incorrect assumptions. My tests were not done on my production code, and were too sloppy. This caused me to draw incorrect conclusions. Basically, what I was testing is if I do a Write(new byte[0]...) on one end, the other end's Read(...) will return 0. It did, but not due to the send. The TcpClient I used to test was falling out of scope, which (I assume) caused it to be Disposed by GC, thus the connection got closed, which caused the Read to return 0. I did repeat the test with TcpClient not being disposed/lost, and the Read does not return anything, no matter how many empty byte arrays I send.

At first, I expected the Nagle's algorithm to mess things up, but it doesn't in this case - 1-byte arrays arrive without delays, as I was testing on localhost. I may do a different test, using Sockets, and explicitly disabling Nagle's algorithm, but I don't think this will change anything.

Now I just need to check whether sending such an array will actually allow me to detect a disconnection, but that is a different story, not in the scope of this question.

EDIT 2: I did some more tests regarding this, and found out, that despite several suggestions, e.g. here (which seems like a valid source of information), doing an empty Send does not recognize a broken connection. I physically disconnected a network cable, and my Server is doing those empty sends every 5 seconds. It's been going like that for several minutes, and no disconnection was detected. If I decide to send any data (even a single byte), the disconnection gets detected after 20 seconds at most.

like image 715
Marcin Pawlica Avatar asked Oct 18 '22 06:10

Marcin Pawlica


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr. Stroustroupe.

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.

How old is the letter C?

The letter c was applied by French orthographists in the 12th century to represent the sound ts in English, and this sound developed into the simpler sibilant s.


1 Answers

From MSDN's NetworkStream.Read Method (Byte[], Int32, Int32):

The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter. If no data is available for reading, the Read method returns 0.


While sending data, you're sending an empty byte array and writing zero bytes using:

networkStream.Write(new byte[0], 0, 0);

Whereas, while reading the data, you claim that

  1. "My client code does expect data from the Server from time to time, so it has a thread that blocks on networkStream."
int bytesRead = networkStream.Read(buffer, 0, 4);
if (bytesRead == 0)
   break;

But, then again you're trying to read 4 bytes to a byte array, which would obviously keep on waiting. So, what else do you expect!

  1. "...just wanted to know if .NET's Socket can distinguish between an empty byte array and connection closing."

Connection closing is totally a different story, which involves several steps before closing of a Socket connection. So, obviously, it is not the same as sending or receiving zero bytes!

-> Lastly, as hinted by @WithMetta in the comments, please check whether the data is available to be read or not using NetworkStream.DataAvailable Property.

while(networkStream.DataAvailable) { // your code logic}
like image 189
Am_I_Helpful Avatar answered Oct 20 '22 05:10

Am_I_Helpful