C#: How do I terminate a socket before Socket.Begi

2019-03-29 10:06发布

问题:

I have a server that receives connection requests from clients. This server makes use of the asynchronous Socket.BeginReceive and Socket.EndReceive method. The code is pretty similar to the code found here.

In my case, after calling Socket.BeginReceive I need a timeout such that if the client hangs on to the connection but does not transmit any data at all for a fixed amount of time, I need to terminate the connection.

  • How do I go about terminating the connection in this scenario?
  • What is the best way of coding a timer?

回答1:

Just call the socket's Close() method. The callback method will run pretty quickly after that, you'll get an ObjectDisposedException when you call the EndReceive() method. Be prepared to catch that exception.

You probably don't want to block the thread that called BeginReceive, you'll need a System.Threading.Timer or System.Timers.Timer to detect the timeout. Its callback should call Close(). Beware of the inevitable race-condition this causes, the timer's callback will run if the response was received a microsecond before the timer expired. You'll close the socket, even though you got a good response. The next call to BeginReceive() will fail immediately.



回答2:

I know this thread is pretty old but I just encountered the same problem and I was not satisfied by the answer given here (or anywhere else by that matter).

A better solution to cancel a pending Socket.BeginReceive is to call Socket.Shutdown and not Socket.Close. This way the asynch handler is raised "normally", and a call to Socket.EndReceive returns 0 --> instead of throwing an ugly expected-exception. You should always have an

if (Socket.EndReceive() > 0) {
  //Do something
} else {
  //Socket has been shut down (either by you or the other end of the connection)
  //Now it's "safe" to call Socket.Close
  Socket.Close();
}

so you don't even need to adjust your asynch-callback to handle the manual cancellation.



回答3:

According to the MSDN article on Socket.BeginReceive it states

To cancel a pending BeginReceive, call the Close method.



回答4:

You can Receive some initial data asynchronously and then make synchronous Receive for rest of the data and rely on ReceiveTimeout to disconnect the client. You can use Socket.Close to forcefully disconnect client.

But if you want to use async Receive only, then you can use timers and reset them on EndReceive. If it elapse you can disconnect the client forcefully.

But I think the first approach is better.