【问题标题】:How to connect to modems with tcp clients, in multiple port or other way?如何以多端口或其他方式连接到带有 tcp 客户端的调制解调器?
【发布时间】:2010-10-27 18:06:14
【问题描述】:

我有大约 5000 个调制解调器(瘦客户端),我想与他们通信,我的方法之一是这样的:string GetModemData(modemID),现在我在服务器中有一个开放端口来监听调制解调器,我正在使用套接字编程向调制解调器发送数据(调用相关函数),但是当我想同时向多个调制解调器发送数据并得到它们的响应时,我不知道该怎么办?我可以将数据发送到一个调制解调器并等待它的响应,然后将另一个数据发送到其他调制解调器(顺序),但问题是客户端应该等待很长时间才能得到答案(可能是一些不同的客户端想要从调制解调器获取一些信息所以他们都将等待进入Q或类似的东西),我认为解决这个问题的一种方法是使用多个端口并监听每个调制解调器到相关端口,但它需要太多端口并且也可能是内存使用量超过我的可用内存空间,因此可能会发生一些丢失(这是真的吗?)。应该怎么做?我会考虑并行性,但我认为它不相关我应该等待一个端口,因为我不知道应该将当前接收到的数据传递给哪个客户端。我正在使用 asp.net。

目前我正在这样做:

private void StartListener()
    {
        ModemTcpListener = new TcpListener(ModemPort);
        //ClientTcpListener = new TcpListener(ClientPort);

        ModemTcpListener.Start();
        ModemTcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptModemCallback), ModemTcpListener);
    }

作为回报

private void DoReadModemCallback(IAsyncResult ar)
         {
             try
             {
                 bool bRet = ar.AsyncWaitHandle.WaitOne(420000);
                 Modem modem = ar.AsyncState as Modem;
                 if (!bRet || modem == null)
                 {
                     return;
                 }
           }
           catch{}
            // now send data to which client?????? if i'm going to use async????
}

和:

private void DoAcceptModemCallback(IAsyncResult ar)
        {
            try
            {
                ModemTcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptModemCallback), ModemTcpListener);
                TcpClient tcpClient = ModemTcpListener.EndAcceptTcpClient(ar);
                Modem modem= new Modem(tcpClient, "");
                tcpClient.GetStream().BeginRead(modem.Buffer, 0, tcpClient.ReceiveBufferSize, new AsyncCallback(DoReadModemCallback), modem);
                ModemTcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptModemCallback), ModemTcpListener);
                Log.Write("a Modem connect ...");
            }
            catch (Exception ex) 
            {
            }
        }

【问题讨论】:

  • 你在 DoAcceptModemCallback 中做了什么?
  • 现在你应该做的是在一个列表中保留对调制解调器对象的引用,但是你仍然有识别调制解调器的问题,调制解调器应用程序是你的我的意思是你写了那个应用程序?因为如果你这样做了,那么你应该让调制解调器在连接到服务器时向你发送一个标识。
  • @A_Nablsi,调制解调器是我的课,我可以跟踪它们,但在客户端我有一个问题(不是瘦客户端,调制解调器是瘦客户端)我找到了一个解决方案,但它很复杂,因为我会做解析算法太多,我想找个简单的方法,现在我也睡了:D
  • 晚安,祝你好运
  • 您应该为此创建一个 Windows 服务。不要使用 asp.net

标签: c# asp.net sockets parallel-processing


【解决方案1】:

这是一个跟踪所有客户的示例。为了便于阅读,我已经对其进行了压缩。你真的应该把它分成多个类。

我正在使用 Pool(我刚刚创建并提交)和 SimpleServer。这两个类都是我目前正在构建的库的一部分(但远未完成)。

不要害怕打开 5000 个套接字,当您使用异步操作时,它们不会消耗太多资源。

    public class SuperServer
    {
        private List<ClientContext> _clients = new List<ClientContext>();
        private SimpleServer _server;
        private Pool<byte[]> _bufferPool;

        public SuperServer()
        {
            // Create a buffer pool to be able to reuse buffers
            // since your clients will most likely connect and disconnect
            // often.
            //
            // The pool takes a anonymous function which should return a new buffer.
            _bufferPool = new Pool<byte[]>(() => new byte[65535]);
        }

        public void Start(IPEndPoint listenAddress)
        {
            _server = new SimpleServer(listenAddress, OnAcceptedSocket);

            // Allow five connections to be queued (to be accepted)
            _server.Start(5); 
        }

        // you should handle exceptions for the BeginSend
        // and remove the client accordingly.
        public void SendToAll(byte[] info)
        {
            lock (_clients)
            {
                foreach (var client in _clients)
                    client.Socket.BeginSend(info, 0, info.Length, SocketFlags.None, null, null);
            }
        }

        // Server have accepted a new client.
        private void OnAcceptedSocket(Socket socket)
        {
            var context = new ClientContext();
            context.Inbuffer = _bufferPool.Dequeue();
            context.Socket = socket;

            lock (_clients)
                _clients.Add(context);

            // this method will eat very few resources and
            // there should be no problem having 5000 waiting sockets.
            context.Socket.BeginReceive(context.Inbuffer, 0, context.Inbuffer.Length, SocketFlags.None, OnRead,
                                        context);
        }

        //Woho! You have received data from one of the clients.
        private void OnRead(IAsyncResult ar)
        {
            var context = (ClientContext) ar.AsyncState;
            try
            {
                var bytesRead = context.Socket.EndReceive(ar);
                if (bytesRead == 0)
                {
                    HandleClientDisconnection(context);
                    return;
                }

                // process context.Inbuffer here.
            }
            catch (Exception err)
            {
                //log exception here.
                HandleClientDisconnection(context);
                return;
            }

            // use a new try/catch to make sure that we start
            // read again event if processing of last bytes failed.
            try
            {
                context.Socket.BeginReceive(context.Inbuffer, 0, context.Inbuffer.Length, SocketFlags.None, OnRead,
                                            context);
            }
            catch (Exception err)
            {
                //log exception here.
                HandleClientDisconnection(context);
            }
        }

        // A client have disconnected.
        private void HandleClientDisconnection(ClientContext context)
        {
            _bufferPool.Enqueue(context.Inbuffer);
            try
            {
                context.Socket.Close();
                lock (_clients)
                    _clients.Remove(context);
            }
            catch(Exception err)
            {
                //log exception
            }
        }


        // One of your modems
        // add your own state info.
        private class ClientContext
        {
            public byte[] Inbuffer;
            public Socket Socket;
        }

    }

使用的类:

【讨论】:

    【解决方案2】:

    您需要使用异步 tcp/ip 方法。本文展示了如何:

    http://www.codeproject.com/KB/IP/asyncsockets.aspx

    关键部分是 BeginReceive() 和相关的回调函数。任何更多的问题,请让 cmets 回答这个问题 ;) 祝你好运!

    【讨论】:

    • 另外,我建议你保留一个打开的连接数组,例如 Socket [] = new Socket[5000];如果你使用异步调用,端口使用和内存应该不是问题,因为处理只会在打开连接、开始接收和接收数据时发生(函数回调)。
    • 那篇文章包含几个可能导致应用程序崩溃或行为异常的缺陷。它可能适用于一个或两个连接的套接字。永远不要像他在文章中那样混合使用线程和异步方法。并且永远不要检查事件是否为 null 然后调用它,该事件可能已在其间被清除。不要吃带有空 catch 块的异常。
    • @jgauffin,我同意你的观点,但是 vdoogs 打开太多套接字并不能解决我的问题,我也应该听哪个调制解调器在哪个套接字中?可能是我不能仔细说出我的问题,请参阅我对 A_Nablsi 的评论。
    【解决方案3】:

    您需要多线程,每当客户端与服务器建立连接时,都会为其启动一个新线程并开始通信发送/接收。

    这里有一些文章解释了 c# 中的多线程, c-sharpcorner codeproject

    这是一个多线程的示例服务器应用程序, http://www.dotnetspider.com/resources/2829-A-multi-readed-server-C-which-finds-prime-num.aspx

    【讨论】:

    • 想想这个场景:你有 5 个不同的客户端,他们想要获取 5 个不同的瘦客户端数据,如果他们在一个端口上侦听,我如何找到接收到的女巫数据让女巫客户端通过它?如果我使用 tcp ip 或像这样连接到客户端,我可以保存他们的 ip 地址(MAC 或 ...)并将数据发送回他们,但我使用 asp.net 只是一些函数调用,我不知道将接收到的数据发送到哪个客户端。因为我不是 IIS 高手所以会做。
    • 我不会为每个客户创建一个新线程,这是一种非常低效的方式。改用异步 IO(BeginRead/EndRead 等)。
    • 请我需要更多解释获取他们的数据。正如我想象的那样,每当客户端与服务器建立连接时,您的应用程序都必须保持对客户端套接字对象的引用,这样您就可以与所有保持其套接字对象引用的客户端异步或通过多线程进行通信。
    • 谢谢,但主要问题是我有 2 种不同类型的客户端:WebClient ----> 请求服务器 ------> 服务器 -------> 请求瘦客户端,现在瘦客户端将发送数据服务器现在服务器应该找到向相关客户端发送数据,问题是这样,我无法确定服务器将接收到的数据发送到哪个客户端,因为它只是来自 iis 的函数调用,服务器将被响应某些优先级的调用可能与瘦客户端的相关响应顺序不同。
    猜你喜欢
    • 2017-07-29
    • 1970-01-01
    • 2017-09-12
    • 2015-08-15
    • 1970-01-01
    • 2015-04-20
    • 1970-01-01
    • 2022-01-17
    • 2010-11-18
    相关资源
    最近更新 更多