最近我在socket中发现了一个问题,导致CLOSE_WAIT,甚至已经关闭并关闭套接字 .

  • 我使用套接字来监听连接,当收到连接时,使用连接接收数据使用BeginReceive,然后接受下一次连接 .

  • 当BeginReceive回调时,使用委托处理数据异步,然后使用BeginReceive接下来,然后关闭并关闭连接 .

  • 客户端连接服务器套接字,然后发送数据,然后在接下来的500~1000ms内关闭套接字 .

  • 重复一段时间,发现了很多CLOSE_WAIT连接,但已经调用了shutdown和close .

  • 控制台输出消息如:epoll_ctl(MOD):17文件存在 .

CentOS 6.2 x64单声道4.0.2

是否有一些身体遇到同样的情况?或者给我一些建议 . 非常感谢 .

示例代码:

public class SocketTest
{
    private const int NET_LISTEN_BACKLOG                            = 128;

    private Socket m_serverSocket                                   = null;

    private Thread m_mainThread                                     = null;

    public int m_acceptNum                                          = 0;

    public SocketTest( )
    {
        m_mainThread = new Thread( new ThreadStart( MainProc ) );
        m_mainThread.Start( );
    }

    public void Startup( int port )
    {
        m_serverSocket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );

        m_serverSocket.Bind( new IPEndPoint( IPAddress.Any, port ) );
        m_serverSocket.Listen( NET_LISTEN_BACKLOG );
        m_serverSocket.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true );
        m_serverSocket.BeginAccept( new AsyncCallback( ServerAcceptCallback ), null );
    }

    private void ServerAcceptCallback( IAsyncResult ar )
    {
        try
        {
            //debug                                                 
            Interlocked.Increment( ref m_acceptNum );


            Socket socket           = m_serverSocket.EndAccept( ar );
            socket.NoDelay = true;

            STcpConnection con      = new STcpConnection( socket );

            con.RecvPakAsync( new SPackRecvCallback( TestProtocolPackRecvCallback ), null );

            m_serverSocket.BeginAccept( new AsyncCallback( ServerAcceptCallback ), null );
        }
        catch( Exception ex )
        {
            Console.WriteLine( "ServerAcceptCallback : " + ex.ToString( ) );
        }
    }

    delegate void STestSendPackDelegate( STcpConnection conn );

    private void TestProtocolPackRecvCallback( STcpConnection conn, bool success, byte[] packData, string errMsg, object state )
    {
        try
        {
            if( !success )
            {
                conn.Close( );
                return;
            }

            STestSendPackDelegate dele = new STestSendPackDelegate( RetPack );
            dele.BeginInvoke( conn, null, null );

            conn.RecvPakAsync( new SPackRecvCallback( TestProtocolPackRecvCallback ), null );

            //here if close the socket, will cause CLOSE_WAIT.
            conn.Close( );
        }
        catch( Exception ex )
        {
            Console.WriteLine( "TestProtocolPackRecvCallback : " + ex.ToString( ) );
        }
    }

    private void RetPack( STcpConnection conn )
    {
        byte[] data = Encoding.ASCII.GetBytes( "Hello" );
        conn.TrySendDataAsync( data );
    }

    private void MainProc( )
    {
        try
        {
            while( true )
            {
                Console.WriteLine( string.Format( "-------------------------- {0} ---------------------------", DateTime.Now.ToString( "yyyy-MM-dd HH:mm:ss" ) ) );
                Console.WriteLine( "m_acceptNum                       : " + m_acceptNum );

                Thread.Sleep( 5000 );
            }
        }
        catch( Exception ex )
        {
            Console.WriteLine( ex.ToString( ) );
        }
    }
}





public delegate void SPackRecvCallback( STcpConnection conn, bool success, byte[] packData, string errMsg, object state );

public class STcpConnection
{
    private Socket m_socket                                     = null;

    public IPAddress IPAddress
    {
        get { return ( ( IPEndPoint )m_socket.RemoteEndPoint ).Address; }
    }

    public int Port
    {
        get { return ( ( IPEndPoint )m_socket.RemoteEndPoint ).Port; }
    }

    public STcpConnection( Socket socket )
    {
        if( socket == null )
            throw new ArgumentNullException( );

        m_socket        = socket;
    }

    ......


    public void Close( )
    {
        try
        {
                try
                {
                    m_socket.Shutdown( SocketShutdown.Both );
                }
                catch( Exception ex )
                {
                    Console.WriteLine( "Close Exception : " + ex.ToString( ) );
                }

                m_socket.Close( );
            }
        }
        catch( Exception ex )
        {
            Console.WriteLine( ex.ToString( ) );
        }
    }

    private void OnPakRecvCallback( SPackRecvCallback cb, object state, bool success, byte[] msg, string errMsg )
    {
        try
        {
            if( cb != null )
            {
                cb( this, success, msg, errMsg, state );
            }
        }
        catch( Exception ex )
        {
            Console.WriteLine( ex.ToString( ) );
        }
    }
}

问题出现在实际项目中,代码是重现问题的核心 . 在项目中我们没有这么近,但在某些情况下会有CLOSE_WAIT .