【问题标题】:TCP Server : "Only one usage of each socket address (protocol/network address/port) is normally permitted."TCP 服务器:“每个套接字地址(协议/网络地址/端口)通常只允许使用一次。”
【发布时间】:2012-04-06 10:02:42
【问题描述】:

我有一个 TCP 服务器(作为 Windows 服务实现)用于侦听车辆跟踪应用程序中的 GPS 设备,在其运行随机一段时间后,我收到以下错误:“每个套接字地址仅使用一次(协议/网络地址/端口)通常是允许的。”虽然我确信在使用它后我会关闭每个套接字。所以谁能告诉我这里有什么问题我在 Windows Server 2008 注册表中有 (65534) 的 MaxUserPort 值和 (30 秒) 的 TCPTimeWaitDelay 值?

代码如下: 1)主线程:

 private void MainThread() {
        byte[] bytes = new Byte[1024];

        IPEndPoint localEndPoint = new IPEndPoint(0, this.port);

        Socket listener = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp );
        // Addedd on [20/03/2012] by Sherif Mosaad for handling socket exceptions ...
        //listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, (int)1);

        try {
            listener.Bind(localEndPoint);
            listener.Listen(100);

            while (active) {
                mainDone.Reset();

                listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);

                while (active)
                    if (mainDone.WaitOne(100, true))
                        break;
            }
            listener.Shutdown(SocketShutdown.Both);
            listener.Close();
            Thread.Sleep(2000);

        } catch (Exception e) {
            if (OnError != null)
                OnError(this, e.ToString());
            LogManager.LogError(e, "TCPSimpleServer MainThread"); 
        }
    }

2) AcceptCallback 处理程序:

private void AcceptCallback(IAsyncResult ar) {
        mainDone.Set();

        Socket listener = (Socket)ar.AsyncState;
        Socket handler = null;
        try
        {
            handler = listener.EndAccept(ar);
        }
        catch 
        {
            try
            {
                listener.Shutdown(SocketShutdown.Both);
                listener.Close();
                Thread.Sleep(2000);
            }
            catch { return; }
        }

        if (OnConnect != null)
            OnConnect(this, handler);

        StateObject state = new StateObject();

        state.workSocket = handler;
        state.endPoint = (IPEndPoint)handler.RemoteEndPoint;
        stateObjectDictionary.Add(state, state.workSocket);
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(ReadCallback), state);
    }

3) ReadCallback 处理程序:

 private void ReadCallback(IAsyncResult ar) {
        String content = String.Empty;
        StateObject state = (StateObject)ar.AsyncState;
        Socket handler = state.workSocket;

        int bytesRead = 0;
        try
        {
            bytesRead = handler.EndReceive(ar);
        }
        catch (Exception e)
        {
            // Connection closed by client
            if (OnDisconnect != null)
                OnDisconnect(this, state.endPoint);
            return;
        }

        if (bytesRead > 0)
        {
            string data = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
            if (OnDataAvailable != null)
                OnDataAvailable(this, handler, data);
            try
            {
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReadCallback), state);
            }
            catch (Exception e)
            {
                // Connection closed by client
                if (OnDisconnect != null)
                    OnDisconnect(this, state.endPoint);
                return;
            }
        }
        else
        {
            // Connection closed by peer
            if (OnDisconnect != null)
                OnDisconnect(this, state.endPoint);
        }
    }

最后是状态对象:

public class StateObject
    {
        public Socket workSocket = null;
        public const int BufferSize = 1024;
        public byte[] buffer = new byte[BufferSize];
        public StringBuilder sb = new StringBuilder();
        public IPEndPoint endPoint;
    }

有什么帮助吗?

【问题讨论】:

  • 在您的第一个代码块中发生异常之后是否会发生这种情况?您可能应该在 finally 块中而不是在 try 本身中清理您的侦听器。

标签: c# sockets tcp port tcplistener


【解决方案1】:

有一个竞争条件。你调用mainDone.Set,它允许另一个线程继续到BeginAccept,而当前线程移动到EndAccept。哪个会先到达那里?如果你在完成之前的接受之前开始接受,我怀疑可能会弹出这个错误。

修复?你需要设置mainDone事件你调用EndAccept

更好的是,遵循没有同步原语的更简单的模式。我概述了一个here

【讨论】:

    猜你喜欢
    • 2019-05-03
    • 2017-06-09
    • 2011-01-15
    • 2010-12-26
    • 2015-05-10
    • 2010-11-23
    相关资源
    最近更新 更多