问题
I am experimenting in creating a small IRC server to learn some new programming concepts (and others I haven't used in forever). The first step is to get a basic client connecting via TCP to send plaintext commands to the server.
To listen for connection I have the following code:
public NetworkClient(Server server, TcpClient socket, int id)
{
_socket = socket;
_id = id;
_server = server;
}
private async void ListenForClients()
{
int numClients = 0;
while (IsRunning)
{
var tcpClient = await _listener.AcceptTcpClientAsync();
var netClient = new NetworkClient(this, tcpClient, numClients);
netClient.Start();
Console.WriteLine("Client Connected");
numClients++;
}
}
Then in my NetworkClient
class my Start()
method looks like:
public async void Start()
{
using (var reader = new StreamReader(_socket.GetStream()))
{
while (_server.IsRunning)
{
var line = await reader.ReadLineAsync();
Console.WriteLine("Client {0} wrote: {1}", _id, line);
}
}
}
This works well while a telnet client is connected, however once I close my telnet client reader.ReadLineAsync();
constantly returns null
. I would add a check to see if line == null
but I'm not sure that is the correct way to detect if a client has disconnected.
To make matters worse, _socket.Connected
is constantly returning true all while nulls are getting "received" by reader.ReadLineAsync()
.
What is the proper way to detect when tcp clients have been disconnected?
回答1:
A read on a TCP/IP socket will return 0 bytes when the connection has been gracefully closed. This situation causes ReadLineAsync to return null. So, yes, you should check for null
and treat it as a graceful socket closure.
Sockets may be closed other ways, too; any socket operation may throw an exception if the socket is abortively closed. If the exception happens at an acceptable part of the protocol (where a close is not considered an error), then you should treat that exception as though it were a graceful closure as well.
Oh, and TcpClient.Connected
(like Socket.Connected
) is practically useless; it only tells you whether the socket was connected, not whether it is connected. Just pretend that property doesn't exist.
Finally, a couple of notes:
- Avoid
async void
. If your methods returnTask
, then you have a "handle" to see when they complete (and whether they raised exceptions). My recent MSDN article explains whyasync void
is not recommended. - It's best to periodically send data over the connection to determine if it is still viable. I wrote a TCP/IP .NET sockets FAQ that covers this in more detail.
来源:https://stackoverflow.com/questions/16138302/how-do-i-detect-when-a-telnet-client-is-improperly-closed-to-a-tcp-server