0

我试图Socket.Select在多线程应用程序中使用,我不想使用async socket,所以这是我的代码:-

 public class Server {
        private TcpListener m_listener;
        private IConnectionFactory m_factory;
        private List<Socket> Sockets = new List<Socket>();
        private ConcurrentDictionary<Socket, Connection> Clients = new ConcurrentDictionary<Socket, Connection>();
        private ConcurrentDictionary<string, ConcurrentQueue<Socket>> Threads = new ConcurrentDictionary<string, ConcurrentQueue<Socket>>();
        private int maxsockets = 0;
        private object sync = new object();

        public Server(string ip, int port, IConnectionFactory factory, int maxsockets) {
            IPAddress ipa = IPAddress.Parse(ip);
            TcpListener listener = new TcpListener(ipa, port);
            this.maxsockets = maxsockets;
            m_listener = listener;
            m_factory = factory;

            int threads = maxsockets <= 100 ? 1 : maxsockets / 100;
            for (int i = 0; i < threads; i++) {
                Thread th = new Thread(HandelSockets);
                th.Name = i.ToString();
                Threads.TryAdd(i.ToString(), new ConcurrentQueue<Socket>());
                th.Start();
            }
        }

        public void HandelSockets() {
            ConcurrentQueue<Socket> queue = Threads[Thread.CurrentThread.Name];
            Connection temp;
            Socket sock;

            while (true) {
                try {
                    lock (sync) {
                        while (queue.TryDequeue(out sock)) {
                            if (Clients.TryGetValue(sock, out temp)) {
                                if (!temp.Alive) {
                                    Sockets.Remove(sock);
                                    Clients.TryRemove(sock, out temp);
                                } else {
                                    temp.Receive();
                                    Console.WriteLine("recved from thread num : " + Thread.CurrentThread.Name);
                                }
                            }
                        }
                    }
                } catch { }
                Thread.Sleep(1);
            }
        }

        public void Run() {
            m_listener.Start();
            Console.WriteLine("listen started");
            Sockets.Add(m_listener.Server);

            while (true) {
                try {
                    var temp_list = Sockets.ToList();
                    Socket.Select(temp_list, null, null, 1000);

                    foreach (Socket socket in temp_list) {
                        if (socket == m_listener.Server) {

                            var sock = m_listener.AcceptSocket();
                            Sockets.Add(sock);
                            Connection conn = m_factory.Create(sock);
                            Clients.TryAdd(sock, conn);
                        } else if (Clients.Count >= maxsockets) {
                            Clients[socket].OnMaxConnections();
                            break;
                        } else {
                            if (!Threads.Values.Any(x => x.Contains(socket))) {
                                var quque = Threads.Values.Where(x => !x.Contains(socket)).OrderBy(x => x.Count).First();
                                lock (sync) {
                                    quque.Enqueue(socket);
                                }
                            }
                            break;
                        }
                    }
                } catch {
                }
            }
        }
    }

问题是一段时间后,其中一个连接的套接字将被延迟,其中一个套接字将停止发送或接收,直到其他套接字之一这样做!或者它可能需要几秒/分钟才能恢复接收和发送!

我不知道为什么会发生这种情况!?也许我选择队列的方式?,我希望有人能指出我可能导致延迟发生的原因,谢谢。

4

1 回答 1

0
lock (sync) {
    while (queue.TryDequeue(out sock)) {
        if (Clients.TryGetValue(sock, out temp)) {
            if (!temp.Alive) {
                Sockets.Remove(sock);
                Clients.TryRemove(sock, out temp);
            } else {
                temp.Receive();
                Console.WriteLine("recved from thread num : " + Thread.CurrentThread.Name);
            }
        }
    }
}

我看不到您对 Connection.Receive 的实现,但如果它是一个阻塞调用,即在它收到数据之前不会返回,那么该线程将持有sync对象上的锁,这会导致您的其他线程等待,因此造成延误。

现在您知道是什么导致了问题,您可以进行必要的更改,但是我强烈建议您使用异步方法,因为它会更好地执行并且完全不需要锁定。

编辑:哦,我刚刚意识到这是一个老问题

于 2013-05-03T02:22:53.603 回答