代码之家  ›  专栏  ›  技术社区  ›  Saeed Amiri

如何通过多端口或其他方式连接到带有tcp客户端的调制解调器?

  •  1
  • Saeed Amiri  · 技术社区  · 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) 
                {
                }
            }
    
    3 回复  |  直到 12 年前
        1
  •  2
  •   jgauffin    14 年前

    下面是一个跟踪所有客户的例子。为了便于阅读,我把它压缩了。你真的应该把它分成多个类。

    我正在使用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
  •  1
  •   justinmvieira    14 年前

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

    关键部分是BeginReceive()和相关的回调函数。如果还有问题,请给这个答案留言;)祝你好运!

        3
  •  1
  •   A_Nabelsi    14 年前

    您需要多线程,每当客户机建立到服务器的连接时,为它启动一个新线程并开始通信发送/接收。

    下面是一些用c#解释多线程的文章, c-sharpcorner codeproject

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