TCP socket.receive() seems to drop packets - c#

I am working on client-server appliction in C#. The comunication between them is with TCP sockets. The server listen on specific port for income clients connection. After a new client arrived, his socket being saved in a socket list. I define every new client socket with receive timeout of 1 ms. To receive from the client sockets without blocking my server I use the threadpool like this:
private void CheckForData(object clientSocket)
{
Socket client = (Socket)clientSocket;
byte[] data = new byte[client.ReceiveBufferSize];
try
{
int dataLength = client.Receive(data);
if (dataLength == 0)// means client disconnected
{
throw (new SocketException(10054));
}
else if (DataReceivedEvent != null)
{
string RemoteIP = ((IPEndPoint)client.RemoteEndPoint).Address.ToString();
int RemotePort = ((IPEndPoint)client.RemoteEndPoint).Port;
Console.WriteLine("SERVER GOT NEW MSG!");
DataReceivedEvent(data, new IPEndPoint(IPAddress.Parse(RemoteIP), RemotePort));
}
ThreadPool.QueueUserWorkItem(new WaitCallback(CheckForData), client);
}
catch (SocketException e)
{
if (e.ErrorCode == 10060)//recieve timeout
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CheckForData), client);
}
else if(e.ErrorCode==10054)//client disconnected
{
if (ConnectionLostEvent != null)
{
ConnectionLostEvent(((IPEndPoint)client.RemoteEndPoint).Address.ToString());
DisconnectClient(((IPEndPoint)client.RemoteEndPoint).Address.ToString());
Console.WriteLine("client forcibly disconected");
}
}
}
}
My problem is when sometimes the client send 2 messages one after another, the server doesn't receive the second message. I checked with wireshark and it shows that both of the messages were received and also got ACK.
I can force this problem to occur when I am putting break point here:
if (e.ErrorCode == 10060)//recieve timeout
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CheckForData), client);
}
Then send the two messages from the client, then releasing the breakpoint.
Does anyone met this problem before?

my problem is when sometimes the client send 2 messages one after another, the server doesn't receive the second message
I think it's much more likely that it does receive the second message, but in a single Receive call.
Don't forget that TCP is a stream protocol - just because the data is broken into packets at a lower level doesn't mean that one "send" corresponds to one "receive". (Multiple packets may be sent due to a single Send call, or multiple Send calls may be coalesced into a single packet, etc.)
It's generally easier to use something like TcpClient and treat its NetworkStream as a stream. If you want to layer "messages" on top of TCP, you need to do so yourself - for example, prefixing each message with its size in bytes, so that you know when you've finished receiving one message and can start on the next. If you want to handle this asynchronously, I'd suggest sing C# 5 and async/await if you possibly can. It'll be simpler than dealing with the thread pool explicitly.

Message framing is what you need to do. Here: http://blog.stephencleary.com/2009/04/message-framing.html
if you are new to socket programming, I recommend reading these FAQs http://blog.stephencleary.com/2009/04/tcpip-net-sockets-faq.html

Related

Listen to responses from 2 TcpClient instances against the same IP, but different ports

I'm working on a TCP connection where my client connects to a server's IP on 2 different ports. So I have 2 instances of TcpClient objects, one connecting to the IP on port 9000 and the other on port 9001.
The aim of 2 connections is that the server uses the active connection on port 9000 to give certain responses to the client frequently, and the client uses these responses to form and send a request on port 9001.
Now, the first time I connect on 9000, I get a response, I then form a request and fire off via 9001. Now I have a feeling I'm doing something wrong with the way I'm managing asynchronous requests to both ports, but I can't figure an alternate way of doing this:
IPAddress IPAddress = IPAddress.Parse("192.168.1.10");
public static async Task ConnectToPort9000()
{
TcpClient TcpClient1 = new TcpClient();
try
{
await TcpClient1.ConnectAsync(IPAddress, 9000);
if (TcpClient1.Connected)
{
byte[] Buffer = new byte[1024];
while (await TcpClient1.GetStream().ReadAsync(Buffer, 0, Buffer.Length) > 0)
{
//Server returns a message on this port
string Port9000Response = Encoding.UTF8.GetString(Buffer, 0, Buffer.Length);
//Setting ConfigureAwait(false) so that any further responses returned
//on this port can be dealt with
await Task.Run(async () =>
{
await SendRequestToPort9001BasedOnResponseAsync(Port9000Response);
}).ConfigureAwait(false);
}
}
}
catch (Exception)
{
throw;
}
}
private async Task SendRequestToPort9001BasedOnResponseAsync(string Port9000Response)
{
//Open connection on port 9001 and send request
TcpClient TcpClient2 = new TcpClient();
await TcpClient2.ConnectAsync(IPAddress, 9001);
if (TcpClient2.Connected)
{
//Handle each string response differently
if (Port9000Response == "X")
{
//Form a new request message to send on port 9001
string _NewRequestMesssage = "Y";
byte[] RequestData = Encoding.UTF8.GetBytes(_NewRequestMesssage);
new SocketAsyncEventArgs().SetBuffer(RequestData, 0, RequestData.Length);
await TcpClient2.GetStream().WriteAsync(RequestData, 0, RequestData.Length);
await TcpClient2.GetStream().FlushAsync();
//Handle any responses on this port
//At this point, based on the request message sent on this port 9001
//server sends another response on **port 9000** that needs separately dealing with
//so the while condition in the previous method should receive a response and continue handling that response again
}
else if (Port9000Response == "A")
{
//Do something else
}
}
}
The issue I am having at the moment is, after I send the request on port 9001, when processing any response messages on port 9001, the server has already sent me a response on port 9000, but my while loop on the first method isn't getting triggered, and it seems like that's because it's still executing the second method to process request/response on port 9001. I tried using ConfigureAwait(false) to basically fire and forget, but it doesn't seem to be working. Am I handling asynchronous processes the wrong way? Or should I look at alternatives such as action/delegates?
The aim of 2 connections is that the server uses the active connection on port 9000 to give certain responses to the client frequently, and the client uses these responses to form and send a request on port 9001.
Please don't do this. Socket programming is hard enough without making it extremely more complicated with multiple connections. Error handling becomes harder, detection of half-open connections becomes harder (or impossible), and communication deadlocks are harder to avoid.
Each socket connection is already bidirectional; it already has two independent streams. The only thing you need to do is always be reading, and send as necessary. The read and write streams are independent, so keep your reads and writes independent.

How to Properly Handle a Socket Client disconnecton in a Socket/Thread list?

I'm fairly new in trying to program with Sockets. I have a class whose instance variables include a client's socket and a client's thread, in the name called clientInfo. I created a list of clientInfos to keep track of the connections going into the server, where I've successfully managed to have multiple clients send messages to each other.
listOfClients.Add(new clientInfo(listen.Accept()));
The thread of the clientInfo is in an infinite loop to always receive incoming data, as shown in the code below. The idea that I had was, if I get an exception from the server trying to receive data from a disconnected client, all I should do is remove the client in the list causing the exception, right?
I would iterate through the clients to find exactly at which spot in the list the error is coming from by sending a heartbeat message. Should sending fail, I now have the exact location of the problematic socket and then I would then close their socket, abort the thread, and remove the clientInfo from the list, right? I hope that I have the right idea for that logic. However, when I do so, I've still yet to truly solve the exception which is why (I think) the code shoots itself in the foot by closing all other connections as well. Honestly, I'm at a loss of what to do to solve this.
There's also the unfortunate factor of sending packets to each socket in the list, where the ObjectDisposedException is raised should I close, abort, and remove a socket from a list. Is there a way to completely remove an item from the list as if it were never added in the first place? I assumed removeAt(i) would have done so, but I'm wrong about that.
I've read many answers stating that the best way to handle clients disconnecting is to use socket.close() and list.removeAt(i). My desired goal is that, even if 98 out of 100 clients unexpectedly lose connection, I would like the remaining two clients to still be able to send each other packets through the server. Am I on the right path or is my approach completely wrong?
byte[] buff;
int readBytes;
while (true) {
try {
buff = new byte[clientSocket.SendBufferSize];
readBytes = clientSocket.Receive(buff);
//This line raises an exception should a client disconnect unexpectedly.
if (readBytes > 0) {
Packet pack = new Packet(buff);
handleData(pack);
}
}
catch(SocketException e) {
Console.WriteLine("A client disconnected!");
for (int i = 0; i < listOfClients.Count; i++) {
try {
string message = "This client is alive!";
Packet heartbeat = new Packet(Packet.PacketType.Send, "Server");
heartbeat.data.Add(message);
clientSocket.Send(heartbeat.toByte());
}
catch (SocketException ex) {
Console.WriteLine("Removing " + listOfClients[i].clientEndPointy.Address + ":" + listOfClients[i].clientEndPointy.Port);
//listOfClients[i].clientSocket.Disconnect(reuseSocket: true);
listOfClients[i].clientSocket.Close();
listOfClients[i].clientThread.Abort();
listOfClients.RemoveAt(i);
}
}
}
}

TCP server only accepts the message from one iOS device at a time

I use c# to create a TCP server to connect to the iOS devices. However, I've found that it can only accept one iOS device at a time. I couldn't figure out what is the problem. Can anyone have a look and see what is the problem?
IPAddress ipadr = IPAddress.Parse(localIP);
System.Net.IPEndPoint EndPoint = new System.Net.IPEndPoint(ipadr, 8060);
newsock.Bind(EndPoint);
newsock.Listen(10);
client = newsock.Accept();
IPEndPoint clientip = (IPEndPoint)client.RemoteEndPoint;
while (true)
{
if (!isDisConnected)
{
data = new byte[1024];
recv = client.Receive(data);
if (recv == 0)
break;
string receivedText = Encoding.ASCII.GetString(data, 0, recv);
}
client.Close();
newsock.Close();
There are two kinds of sockets: The socket that you use to listen (it is never connected) and the sockets that correspond to connections (each socket represents one connection).
Accept returns you a connected socket to the client that was just accepted. Each call to Accept accepts a new, independent client.
If you want to handle more than one client at a time (which is almost always required) you must ensure that a call to Accept is pending at all times so that new clients can be accepted.
A simple model to achieve this is to accept in a loop forever and start a thread for each client that you accepted:
while (true) {
var clientSocket = listeningSocket.Accept();
Task.Factory.StartNew(() => HandleClient(clientSocket));
}
Take a look at AcceptAsync. Each accept operation allows one connection, so you have to call Accept again. AcceptAsync works asychronously and avoids the difficulties of having to create delegates or threads.
The general model is:
Accept operation completes
Hand off AcceptSocket to code that will Receive data asychronously from that socket.
Call Accept again to listen for more clients.
The same principle also works if you want to do synchronous receives.
Check out this question: Server design using SocketAsyncEventArgs

TcpListener: Detecting a client disconnect as opposed to a client not sending any data for a while

I was looking how to detect a 'client disconnect' when using a TcpListener.
All the answers seem to be similar to this one:
TcpListener: How can I detect a client disconnect?
Basically, read from the stream and if Read() returns 0 the client had disconnected.
But that's assuming that a client disconnects after every single stream of data it sent.
We operate in environments where the TCP connect/disconnect overhead is both slow and expensive.
We establish a connection and then we send a number of requests.
Pseudocode:
client.Connect();
client.GetStatus();
client.DoSomething();
client.DoSomethingElse();
client.AndSoOn();
client.Disconnect();
Each call between Connect and Disconnect() sends a stream of data to the server.
The server knows how to analyze and process the streams.
If let the TcpListener read in a loop without ever disconnecting it reads and handles all the messages, but after the client disconnects, the server has no way of knowing that and
it will never release the client and accept new ones.
var read = client.GetStream().Read(buffer, 0, buffer.Length);
if (read > 0)
{
//Process
}
If I let the TcpListener drop the client when read == 0 it only accepts
the first stream of data only to drop the client immediately after.
Of course this means new clients can connect.
There is no artificial delay between the calls,
but in terms of computer time the time between two calls is 'huge' of course,
so there will always be a time when read == 0 even though that does not mean
the client has or should be disconnected.
var read = client.GetStream().Read(buffer, 0, buffer.Length);
if (read > 0)
{
//Process
}
else
{
break; //Always executed as soon as the first stream of data has been received
}
So I'm wondering... is there a better way to detect if the client has disconnected?
You could get the underlying socket using the NetworkStream.Socket property and use it's Receive method for reading.
Unlike NetworkStream.Read, the linked overload of Socket.Receive will block until the specified number of bytes have been read, and will only return zero if the remote host shuts down the TCP connection.
UPDATE: #jrh's comment is correct that NetworkStream.Socket is a protected property and cannot be accessed in this context. In order to get the client Socket, you could use the TcpListener.AcceptSocket method which returns the Socket object corresponding to the newly established connection.
Eren's answer solved the problem for me. In case anybody else is facing the same issue
here's some 'sample' code using the Socket.Receive method:
private void AcceptClientAndProcess()
{
try
{
client = server.Accept();
client.ReceiveTimeout = 20000;
}
catch
{
return;
}
while (true)
{
byte[] buffer = new byte[client.ReceiveBufferSize];
int read = 0;
try
{
read = client.Receive(buffer);
}
catch
{
break;
}
if (read > 0)
{
//Handle data
}
else
{
break;
}
}
if (client != null)
client.Close(5000);
}
You call AcceptClientAndProcess() in a loop somewhere.
The following line:
read = client.Receive(buffer);
will block until either
Data is received, (read > 0) in which case you can handle it
The connection has been closed properly (read = 0)
The connection has been closed abruptly (An exception is thrown)
Either of the last two situations indicate the client is no longer connected.
The try catch around the Socket.Accept() method is also required
as it may fail if the client connection is closed abruptly during the connect phase.
Note that did specify a 20 second timeout for the read operation.
The documentation for NetworkStream.Read does not reflect this, but in my experience, 'NetworkStream.Read' blocks if the port is still open and no data is available, but returns 0 if the port has been closed.
I ran into this problem from the other side, in that NetworkStream.Read does not immediately return 0 if no data is currently available. You have to use NetworkStream.DataAvailable to find out if NetworkStream.Read can read data right now.

Disconnecting TCPClient and seeing that on the other side

i am trying to disconnect a client from a server but the server still sees it as being connected. I cant find a solution to this and Shutdown, Disconnect and Close all dont work.
Some code for my disconnect from the client and checking on the server:
Client:
private void btnDisconnect_Click(object sender, EventArgs e)
{
connTemp.Client.Shutdown(SocketShutdown.Both);
connTemp.Client.Disconnect(false);
connTemp.GetStream().Close();
connTemp.Close();
}
Server:
while (client != null && client.Connected)
{
NetworkStream stream = client.GetStream();
data = null;
try
{
if (stream.DataAvailable)
{
data = ReadStringFromClient(client, stream);
WriteToConsole("Received Command: " + data);
}
} // So on and so on...
There are more writes and reads further down in the code.
Hope you all can help.
UPDATE: I even tried passing the TCP client by ref, assuming there was a scope issue and client.Connected remains true even after a read. What is going wrong?
Second Update!!:
Here is the solution. Do a peek and based on that, determine if you are connected or not.
if (client.Client.Poll(0, SelectMode.SelectRead))
{
byte[] checkConn = new byte[1];
if (client.Client.Receive(checkConn, SocketFlags.Peek) == 0)
{
throw new IOException();
}
}
Here is the solution!!
if (client.Client.Poll(0, SelectMode.SelectRead))
{
byte[] checkConn = new byte[1];
if (client.Client.Receive(checkConn, SocketFlags.Peek) == 0)
{
throw new IOException();
}
}
From the MSDN Documentation:
The Connected property gets the
connection state of the Client socket
as of the last I/O operation.
When it
returns false, the Client socket was
either never connected, or is no
longer connected. Because the
Connected property only reflects the
state of the connection as of the most
recent operation, you should attempt
to send or receive a message to
determine the current state. After the
message send fails, this property no
longer returns true. Note that this
behavior is by design. You cannot
reliably test the state of the
connection because, in the time
between the test and a send/receive,
the connection could have been lost.
Your code should assume the socket is
connected, and gracefully handle
failed transmissions.
I am not sure about the NetworkStream class but I would think that it would behave similar to the Socket class as it is primarily a wrapper class. In general the server would be unaware that the client disconnected from the socket unless it performs an I/O operation on the socket (a read or a write). However, when you call BeginRead on the socket the callback is not called until there is data to be read from the socket, so calling EndRead and getting a bytes read return result of 0 (zero) means the socket was disconnected. If you use Read and get a zero bytes read result I suspect that you can check the Connected property on the underlying Socket class and it will be false if the client disconnected since an I/O operation was performed on the socket.
It's a general TCP problem, see:
How do I check if a SSLSocket connection is sane on Java?
Java socket not throwing exceptions on a dead socket?
The workaround for this tend to rely on sending the amount of data to expect as part of the protocol. That's what HTTP 1.1 does using the Content-Length header (for a entire entity) or with chunked transfer encoding (with various chunk sizes).
Another way is to send "NOOP" or similar commands (essentially messages that do nothing but make sure the communication is still open) as part of your protocol regularly.
(You can also add to your protocol a command that the client can send to the server to close the connection cleanly, but not getting it won't mean the client hasn't disconnected.)

Categories

Resources