I've already looked up the definitions and all but since I am dealing with server code I wanna know EXACTLY what is going on here.
So the way I'm interpreting it so far is that a SocketException happens if something outside of the program happens to the socket; such as, the network going down or the client closing the connection on his end. Meaning I have to call shutdown and close on my end? Is this how I'm supposed to detect that a client shuts down the connection? When an exception is thrown?
The way I'm interpreting the ObjectDisposedException is that it occurs when I called shutdown and close on that socket from another thread or something and I am still using the dead socket somewhere else.
Related
I have an application that sends data over TCP using a Socket (System.Net.Sockets.Socket). I indicate that all data has been sent, by doing a graceful disconnect (shutting down sending):
Socket.Shutdown(SocketShutdown.Send);
Socket.Close();
Question:
Is it possible that the other side receives a graceful disconnect, without me calling Socket.Shutdown(SocketShutdown.Send))? For example by:
the operating system
or the socket being disposed
or me calling Socket.Close, without first calling
Socket.Shutdown(SocketShutdown.Send)
Background
The reason i'm asking is that i suspect a graceful disconnect happened, without me explicitly doing it. If i can't rely on this, then i might have to resort to reserving a special value to indicate the end of the stream, which i would rather not do
Background
On Linux or BSD, it is possible to send handles to open files or sockets between unrelated processes with SCM_RIGHTS, and I have this working, such that on process is listening for connections, and then forwards the handles to a process that performs the communication.
Problem
I am unable to figure out how to free the socket handle from the listening process without shutting down the socket.
There are two conflicting descriptions in man close(3):
When all file descriptors associated with an open file description have been closed, the open file description shall be freed.
And
If fildes refers to a socket, close() shall cause the socket to be destroyed.
I originally thought that this means that calling close() will just decrement the reference count for the kernel object that has the socket, such that the last description from man close(3) meant "destroy when the last descriptor is closed".
EDIT: This is how it is supposed to work, and also how it works.
But, when I run tests, it appears that as soon as I call close() on the socket descriptor in the listening process, it will start closing the socket, sending either RST or FIN, depending on what the other process is doing with the socket at the time.
One solution would be to have a callback from the handing process with "you can now close socket nnn", but this would keep a number of socket descriptors open in the listening process and add some overhead as well.
I know I can force the socket to start the shutdown process by calling shutdown() directly from either process, but I want to prevent it.
I assume there exists a simple solution, but I cannot find it.
Question
Is there a way to de-register the socket descriptor from the listening process such that it is no longer in the file descriptor table of the process, but without activating the socket shutdown?
Source code
The SCM_RIGHTS implementation used to send the socket is here (send_fds and native_close):
https://github.com/kenkendk/SockRock/blob/master/src/ScmRightsImplementation.cs
The code that sends the socket and then closes it is here:
https://github.com/kenkendk/ceenhttpd/blob/master/Ceen.Httpd.Cli/Runner/SubProcess/SpawnRemoteInstance.cs#L488-L497
If I comment out line 497 everything works, but obviously get a large file descriptors leak.
The receiving end of SCM_RIGHTS is here:
https://github.com/kenkendk/ceenhttpd/blob/master/Ceen.Httpd.Cli/Runner/SubProcess/SpawnedRunner.cs#L313
tl;dr: The socket is closed when the last reference is closed.
The answer to my question is most likely:
No, there is no way to prevent the socket shutdown, but it is not needed as the socket will not close until the last descriptor has closed.
The answer from Andrew was correct, and got me on track: it makes no sense, others do the same all the time.
In the end, the problem was a timeout in the handler process that closed the socket, but that made it look like the close() call from the listener was the problem.
When I stopped the close() call from the listening process, it started working. This happens because then the timeout correctly closes the handle, but there is still a reference (in the listening process) so the socket stays open.
just searched for a posibble solution to indetify when the client disconnecets.
i found this:
public bool IsConnected( Socket s)
{
try
{
return !(s.Poll(1, SelectMode.SelectRead) &&s.Available == 0);
}
catch (SocketException) { return false; }
}
im using a while loop in my main with thread.sleep(500) and running the Isconnectedmthod it works allright when i run it through the visual studio and when i click stop debugging it actually notify me in the server side program but when i just go to the exe in the bin directory and launch it-it's Indeed notify me for a connection but when i close the program (manually from the 'x' button) or through the task manager theIsConnected method apparently return still true.....
im using a simple tcp connection
client = new TcpClient();
client.Connect("10.0.0.2", 10);
server:
Socket s = tcpClient.Client;
while(true)
{
if (!IsConnected(s))
MessageBox.Show("disconnected");
}
(it's running on a thread btw).
any suggestion guys?
i even tried to close the connection when the client closes:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
client.Close();
s.Close();
Environment.Exit(0);
}
dont know what to do
What you are asking for is not possible. TCP will not report an error on the connection unless an attempt is made to send on the connection. If all your program ever does is receive, it will never notice that the connection no longer exists.
There are some platform-dependent exceptions to this rule, but none involving the simple disappearance of the remote endpoint.
The correct way for a client to disconnect is for it to gracefully close the connection with a "shutdown" operation. In .NET, this means the client code calls Socket.Shutdown(SocketShutdown.Send). The client must then continue to receive until the server calls Socket.Shutdown(SocketShutdown.Both). Note that the shutdown "reason" is generally "send" for the endpoint initiating the closure, and "both" for the endpoint acknowledging and completing the closure.
Each endpoint will detect that the other endpoint has shutdown its end by the completion of a receive operation with 0 as the byte count return value for that operation. Neither endpoint should actually close the socket (i.e. call Socket.Close()) until this two-way graceful closure has completed. I.e. each endpoint has both called Socket.Shutdown() and seen a zero-byte receive operation completion.
The above is how graceful closure works, and it should be the norm for server/client interactions. Of course, things do break. A client could crash, the network might be disconnected, etc. Typically, the right thing to do is to delay recognition of such problems as long as possible; for example, as long as the server and client have no need to actually communicate, then a temporary network outage should not cause an error. Forcing one is pointless in that case.
In other words, don't add code to try to detect a connection failure. For maximum reliability, let the network try to recover on its own.
In some less-common cases, it is desirable to detect connection failures earlier. In these cases, you can enable "keep alive" on the socket (to force data to be sent over the connection, thus detecting interruptions in the connection…see SocketOptionName.KeepAlive) or implement some timeout mechanism (to force the connection to fail if no data is sent after some period of time). I would generally recommend against the use of this kind of technique, but it's a valid approach in some cases.
I have a problem with sockets. This:
When client-thread ends, server trying to read, and its freezes, because socket is not closed. Thread dont close it, when its over. Its problem exist, if i using thread, but if i using two independents projects, i have no problem (exception throws, and i can catch it).
I cant use timeout, and i must correct continue server-work, when client dont close socket.
Sorry for my bad eng.
As far as I know, there is no way for TCP server (listener) to find out whether data from client are not coming because it has died/quit or is just inactive. This is not .NET's defficiency, it is how TCP works. The way I deal with it is:
1. Create a timer in my client that periodically sends signal "I am alive" to the server. For example, I just send 1 unusual ASCII character '∩' (code 239).
2. In TCP listener: use NetworkStream.Read(...) method that allows to specify timeout. If timeout expires, the server disposes the old NetworkStream instance and creates new one on the same TCP port. If the server receives "I am alive" signal from client, it keeps listening.
By the way, the property TcpClient.Connected is useless for detecting on server side whether client still uses the socket. The method only returns true if last Read action returned something. So, if client is alive and just silent, the TcpClient.Connected becomes false.
Close client when you want the connection to be closed (at the end of Client).
Better yet, use using for all disposable resources such as both clients and the listener.
Just to be clear, all of the TCPClients I'm referring to here are not instances of my own class, they are all instances of System.Net.Sockets.TcpClient from Mono's implementation of .NET 4.0.
I have a server that is listening for client connections, as servers do. Whenever it gets a new client it creates a new TCPClient to handle the connection on a new thread. I'm keeping track of all the connections and threads with a dictionary. If the client disconnects, it sends a disconnect message to the server, the TCPClient is closed, the dictionary entry is removed and the thread dies a natural death. No fuss, no muss. The server can handle multiple clients with no problem.
However, I'm simulating what happens if the client gets disconnected, doesn't have a chance to send a disconnect message, then reconnects. I'm detecting whether a client has reconnected with a username system (it'll be more secure when I'm done testing). If I just make a new TCPClient and leave the old one running, the system works just fine, but then I have a bunch of useless threads lying around taking up space and doing nothing. Slackers.
So I try to close the TCPClient associated with the old connection. When I do that, the new TCPClient also dies and the client program throws this error:
E/mono (12944): Unhandled Exception: System.IO.IOException: Write failure ---> System.Net.Sockets.SocketException: The socket has been shut down
And the server throws this error:
Unable to write data to the transport connection: An established connection was aborted by the software in your host machine.
Cannot read from a closed TextReader.
So closing the old TCPClient with a remote endpoint of say: 192.168.1.10:50001
Also breaks the new TCPClient with a remote endpoint of say:192.168.1.10:50002
So the two TCPClient objects have the same remote endpoint IP address, but different remote endpoint ports. But closing the one seems to stop the other from working. I want to be able to close the old TCPClient to do my cleanup, without closing the new TCPClient.
I suspect this is something to do with how TCPClient works with sockets at a low level, but not having any real understanding of that, I'm not in a position to fix it.
I had a similar issue on my socket server. I used a simple List instead of a dictionary to hold all of my current connections. In a continuous while loop that listens for new streams, I have a try / catch and in the catch block it kills the client if it has disconnected.
Something like this on the sever.cs:
public static void CloseClient(SocketClient whichClient)
{
ClientList.Remove(whichClient);
whichClient.Client.Close();
// dispose of the client object
whichClient.Dispose();
whichClient = null;
}
and then a simple dispose method on the client:
public void Dispose()
{
System.GC.SuppressFinalize(this);
}
EDIT: this paste is the OPs resolution which he or she found on their own with help from my code.
So to clarify, the situation is that I have two TCPClient objects TCPClientA and TCPClientB with different remote endpoints ports, but the same IP:
TCPClientA.Client.RemoteEndPoint.ToString();
returns: 192.168.1.10:50001
TCPClientB.Client.RemoteEndPoint.ToString();
returns: 192.168.1.10:50002
TCPClientA needs to be cleaned up because it's no longer useful, so I call
TCPClientA.Close();
But this closes the socket for the client at the other end of TCPClientB, for some reason. However, writing
TCPClientA.Client.Close();
TCPClientA.Close();
Successfully closes TCPClientA without interfering with TCPClientB. So I've fixed the problem, but I don't understand why it works that way.
Looks like you have found a solution but just so you are aware there are many similar pitfalls when writing client/server applications in .net. There is an open source network library (which is fully supported in mono) where these problems have already been solved, networkComms.net. A basic sample is here.
Disclaimer: This is a commercial product and I am the founder.
This is clearly an error in your code. Merely closing one inbound connection cannot possibly close another one. Clearly something else is happening elsewhere in your code.