一段时间后,套接字从队列中延迟

时间:2013-04-03 18:24:30

标签: c# multithreading sockets select concurrent-collections

我正在尝试在多线程应用程序中使用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 {
                }
            }
        }
    }

问题是一段时间后,其中一个连接的套接字将被延迟,其中一个套接字将停止发送或接收,直到其中一个套接字执行此操作!或者它可能需要几秒/分钟才能恢复接收并发送!

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

1 个答案:

答案 0 :(得分: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对象上的锁定导致其他线程等待,从而导致延迟。

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

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