最近遇到一个问题,linux 的client端改变IP地址后再次连接Windows server端, server不会得到任何连接关闭的通知,用命令:
netstat -anop tcp | find "4114" ,发现连接依然是established状态:
C:\Documents and Settings\riverli>netstat -anop tcp | find "4114"
TCP 0.0.0.0:4114 0.0.0.0:0 LISTENING 9056
TCP 172.26.0.99:4114 172.26.0.244:35578 ESTABLISHED 9056
这样如果client端不断地变换IP,那么server端将会有大量的假连接,这是我们不希望看到的。我们希望server也能及时关闭连接释放这些资源。那么如何做呢?
经过google和多方位的实际测试,以下方式是可行的,希望对大家有帮助:
首先需要指定tcp连接的心跳机制,
tcpServer = new TcpServer(4114);
tcpServer.Connected += new TcpServer.TcpServerEventDlgt(OnConnected);
tcpServer.StartListening();
void OnConnected(object sender, TcpServerEventArgs e)
{
// Handle the connection here by starting your own worker thread
// that handles communicating with the client.
try
{
e.ConnectionState.Connection.IOControl(IOControlCode.KeepAliveValues,
Constants.Constant.KEEPALIVE_VALUES_FB, null);
}
catch (System.Exception ex)
{
log("Exception occurred in setting TCP KeepAlive exp={0}", ex.Message);
}
Thread t = new Thread(new ThreadStart(WorkerThread));
t.Start();
}
其次在线程函数WorkerThread中不断检测socket的状态
internal void WorkerThread()
{
try
{
netstream = new NetworkStream(e.ConnectionState.Connection);
{
int nCount = 0;
while (isRunning && isKeepRunningFromRunCommand)
{
nCount++;
if (nCount == 100)
{
nCount = 0;
if (!e.ConnectionState.isConnected())
break;
}
while (netstream.DataAvailable)
{
processIncomingData();
}
Thread.Sleep(100);
}
log(remoteHost + ": Closing connection");
}
}
catch (Exception exp)
{
//an error happened, log it and close the thread
log("The remote host has disconnected. Exception={0}", getExceptionMessage(exp));
}
e.ConnectionState.Close();
注意看上面的代码,每10 秒钟调用e.ConnectionState.isConnected()去探测一下socket的连接状态,此函数的代码参考msdn,如下:// This is how you can determine whether a socket is still connected. public bool isConnected() { bool blockingState = connection.Blocking; try { byte[] tmp = new byte[1]; connection.Blocking = false; connection.Send(tmp, 0, 0); return connection.Connected; } catch (SocketException e) { // 10035 == WSAEWOULDBLOCK if (e.NativeErrorCode.Equals(10035)) { //Still Connected, but the Send would block return true; } else { //Disconnected: error code {0}!", e.NativeErrorCode); return false; } } finally { connection.Blocking = blockingState; } }
connection是Socket类型。
这样如果client端改变IP,几秒钟后调用send函数就会抛出连接关闭的异常。