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.)
Related
First, I don't know if Stackoverflow is the best site to post this kind of message, but I don't know another sites like this.
In oder to understand properly tcp programmation in C#, I decided to do all possible ways from scratch. Here is what I want to know (not in the right order:
- Simple One Thread Socket Server (this article)
- Simple Multiple Threads Socket Server (I don't know how, cause threads are complicated)
- Simple Thread Socket Server (put the client management in another thread)
- Multiple Threads Socket Server
- Using tcpListener
- Using async / Await
- Using tasks
The ultimate objective is to know how to do the best tcp server, without just copy/paste some parts of come, but understand properly all things.
So, this is my first part : a single thread tcp server.
There is my code, but I don't think anybody will correct something, because it's quite a copy from MSDN : http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace SimpleOneThreadSocket
{
public class ServerSocket
{
private int _iPport = -1;
private static int BUFFER_SIZE = 1024;
private Socket _listener = null;
public ServerSocket(int iPort)
{
// Create a TCP/IP socket.
this._listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Save the port
this._iPport = iPort;
}
public void Start()
{
byte[] buffer = null;
String sDatasReceived = null;
// Bind the socket to loopback address
try
{
this._listener.Bind(new System.Net.IPEndPoint(System.Net.IPAddress.Loopback, _iPport));
this._listener.Listen(2);
}
catch (Exception e)
{
System.Console.WriteLine(e.ToString());
}
// Listening
try
{
Console.WriteLine("Server listening on 127.0.0.1:" + _iPport);
while (true)
{
Socket client = this._listener.Accept();
Console.WriteLine("Incoming connection from : " + IPAddress.Parse(((IPEndPoint)client.RemoteEndPoint).Address.ToString()) + ":" + ((IPEndPoint)client.RemoteEndPoint).Port.ToString());
// An incoming connection needs to be processed.
while (true)
{
buffer = new byte[BUFFER_SIZE];
int bytesRec = client.Receive(buffer);
sDatasReceived += Encoding.ASCII.GetString(buffer, 0, bytesRec);
if (sDatasReceived.IndexOf("<EOF>") > -1)
{
// Show the data on the console.
Console.WriteLine("Text received : {0}", sDatasReceived);
// Echo the data back to the client.
byte[] msg = Encoding.ASCII.GetBytes(sDatasReceived);
client.Send(msg);
sDatasReceived = "";
buffer = null;
}
else if (sDatasReceived.IndexOf("exit") > -1)
{
client.Shutdown(SocketShutdown.Both);
client.Close();
sDatasReceived = "";
buffer = null;
break;
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
But I have some questions about that :
Listen Method from Socket have a parameter : backlog. According to MSDN, backlog is the number of available connection. I don't know why, when I put 0, I can connect to my server with multiple Telnet sessions. EDIT : 0 & 1 both allow 2 connections (1 current, 1 pending), 2 allow 3 connections (1 current, 2 pending), etc... So I didn't understand well the meaning of MSDN.
Can you confirm that Accept Method will take each connection one after one, that's why I see text from differents Telnet session in my server ?
Can you confirm (my server is a C# library) I can't kill my server (with this kind of code) without killing the process ? It could be possible with threads but it will come later.
If something is wrong in my code, please help me :)
I will come back soon with a simple multiple thread socket server, but I don't know how (I think one step is available before using threads or async/await).
First off, do your best not to even learn this. If you can possibly use a SignalR server, then do so. There is no such thing as a "simple" socket server at the TCP/IP level.
If you insist on the painful route (i.e., learning proper TCP/IP server design), then there's a lot to learn. First, the MSDN examples are notoriously bad starting points; they barely work and tend to not handle any kind of error conditions, which is absolutely necessary in the real world when working at the TCP/IP level. Think of them as examples of how to call the methods, not examples of socket clients or servers.
I have a TCP/IP FAQ that may help you, including a description of the backlog parameter. This is how many connections the OS will accept on your behalf before your code gets around to accepting them, and it's only a hint anyway.
To answer your other questions: A single call to Accept will accept a single new socket connection. The code as-written has an infinite loop, so it will work like any other infinite loop; it will continue executing until it encounters an exception or its thread is aborted (which happens on process shutdown).
If something is wrong in my code, please help me
Oh, yes. There are lots of things wrong with this code. It's an MSDN socket example, after all. :) Off the top of my head:
The buffer size is an arbitrary value, rather low. I would start at 8K myself, so it's possible to get a full Ethernet packet in a single read.
The Bind explicitly uses the loopback address. OK for playing around, I guess, but remember to set this to IPAddress.Any in the real world.
backlog parameter is OK for testing, but should be int.MaxValue on a true server to enable the dynamic backlog in modern server OSes.
Code will fall through the first catch and attempt to Accept after a Bind/Listen failed.
If any exception occurs (e.g., from Listen or Receive), then the entire server shuts down. Note that a client socket being terminated will result in an exception that should be logged/ignored, but it would stop this server.
The read buffer is re-allocated on each time through the loop, even though the old buffer is never used again.
ASCII is a lossy encoding.
If a client cleanly shuts down without sending <EOF>, then the server enters an infinite busy loop.
Received data is not properly separated into messages; it is possible that the echoed message contains all of one message and part of another. In this particular example it doesn't matter (since it's just an echo server and it's using ASCII instead of a real encoding), but this example hides the fact that you need to handle message framing properly in any real-world application.
The decoding should be done after the message framing. This isn't necessary for ASCII (a lossy encoding), but it's required for any real encodings like UTF8.
Since the server is only either receiving or sending at any time (and never both), it cannot detect or recover from a half-open socket situation. A half-open socket will cause this server to hang.
The server is only capable of a single connection at a time.
That was just after a brief readthrough. There could easily be more.
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
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.
I am writing a socket server and I noticed that if it received an empty socket buffer, it will cause a socketexception. In the receive call, how can I detect and handle the empty buffer and send a -1 response back to the client before the socket closes?
Code:
try
{
byte[] byteBuffer = new Byte[1024];
int size = m_clientSocket.Receive(byteBuffer);
if (size > 0)
{
ParseReceiveBuffer(byteBuffer, size);
}
else
{
m_clientSocket.Send(BitConverter.GetBytes(-1));
}
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.WouldBlock ||
ex.SocketErrorCode == SocketError.IOPending ||
ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
{
// socket buffer is probably empty, wait and try again
Thread.Sleep(1000);
}
// connection was unexpectively closed
}
Assuming you are working with TCP layer.
Sockets functions like Send and Receive are not actually sending or receiving data over network. They communicate with OS sockets layers to push or pop data from networking layer.
Due to this, when you run from your application method Send, it will put in queue data to send into OS networking layer. Only after that OS will actually send it and might get some issues, so that way it will store error and will throw it straight on next that specific socket method call from your application.
That is why you receive SocketException only on next call when previous might was failed or in between previous and current call network had some error (for example connection lose).
When exception is going to be received you will always receive nothing (zero bytes).
You cannot send anything after exception, due to connection lose (in most (99%) cases).
Client will receive exception as well that will have Error message about connection lose.
using DataAvailable clause in appropriate use.
i recommend you write complete class and helper methods for doing all of these regular.
and thread.sleep(1000) is not necessary since listener will wait for your command line to be executed.
another approach is using developed socket library that you can easily simulate both server and client roles.i know supersocket with that you can customize and develop your own protocol.
I have an application that uses TcpClient and TcpListener to communicate over the network. However, when I call TcpClient.Close on the client to disconnect it from the server, the server doesn't react at all.
Now, before you post a comment about this question being a duplicate of this one, and how the solution can be found here, believe me when I say that I've already found these and tried them. It doesn't help. I've also tried different combinations of TcpClient.Close, TcpClient.GetStream().Close(), and TcpClient.Dispose. Nothing works.
The code is nothing noteworthy, just a Disconnect method in the client that resets all of the variables for reuse, and closes all network resources. The server has a loop that checks if TcpClient.Connected is true or not, and if it's false, it's supposed to jump out of the loop and terminate the thread.
Any ideas?
The TcpClient.Connected should pretty much be ignored. It basically represents whether the last communication was successful. From MSDN (emphasis mine):
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.
If you call Close() on the client side, nothing is sent to the server to tell it that its closing, it literally just closes it self so that the client can't use it any more. The only reliable way to determine if you're still connected is to try to send data and handle the failure. If you want you could implement your own handshake agreement where when you call Close() you send a special notification to the server alerting it to the fact but there will still be times when that packet never reaches the server.
Listen for one byte, if it's received, get the rest.
If Receiving the one byte returns 0, client disconnected.
IPAddress nReceiveAddress = IPAddress.Parse(GetIp(sSource));
IPEndPoint localEndPoint = new IPEndPoint(nReceiveAddress, GetPort(sSource));
Socket nSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
nSocket.Bind(localEndPoint);
nSocket.Listen(10);
Socket nSocketClient = nSocket.Accept();
byte[] bufferOne = new byte[1];
int nBytes = nClient.Receive(bufferOne);
if (nBytes == 0)
{
AppendToLog(String.Format("{0}: Closing.", sName));
nClient.Close();
}
else
{
byte[] buffer = null;
buffer = new byte[nClient.Available + 1];
if (nClient.Available > 0)
nBytes = nClient.Receive(buffer);
if(nBytes>0)
{
//KS effectively insert the first received byte at start.
Array.Copy(buffer, 0, buffer, 1, buffer.Length - 1);
buffer[0] = bufferOne[0];
}
}