如何连接使用TCP客户端调制解调器,在多个港口或其他方式? [英] How to connect to modems with tcp clients, in multiple port or other way?

查看:104
本文介绍了如何连接使用TCP客户端调制解调器,在多个港口或其他方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我身边有5000调制解调器(瘦客户机),我想与他们沟通的一个我的方法是这样的:字符串GetModemData(modemID),现在我在服务器开放端口侦听调制解调器和我使用套接字编程将数据发送到调制解调器(调用相关功能),但是当我想要在同一时间发送数据到多个调制解调器,并从他们那里得到,我不回应知道我应该怎么办?我可以将数据发送到一个调制解调器,并等待其响应,然后发送另一个数据到其它调制解调器(顺序),但问题是,客户端应该等待很长时间才能得到答案(可能会有一些不同的客户端想从调制解调器一些信息所以,他们都将等待进入Q或像这样),我想一个办法来解决这个问题是使用多端口,侦听每个调制解调器相关接口,但它需要太多的端口,也可以是内存使用率会并超过我的可用内存空间,所以有些失落可能会发生(这是真的吗?)。应该怎样做?我已经想平行,但我认为,它不涉及我应该等待一个端口,因为我不知道应该到目前接收到的数据传送到哪个客户端。我使用asp.net。

目前我在做这样的:

 私人无效StartListener()
    {
        ModemTcpListener =新的TcpListener(ModemPort);
        // ClientTcpListener =新的TcpListener(CLIENTPORT);        ModemTcpListener.Start();
        ModemTcpListener.BeginAcceptTcpClient(新的AsyncCallback(DoAcceptModemCallback),ModemTcpListener);
    }

和回报

 私人无效DoReadModemCallback(IAsyncResult的AR)
         {
             尝试
             {
                 布尔BRET = ar.AsyncWaitHandle.WaitOne(420000);
                 调制解调器调制解调器= ar.AsyncState作为调制解调器;
                 如果(!BRET ||调制解调器== NULL)
                 {
                     返回;
                 }
           }
           抓住{}
            //现在将数据发送到哪个客户端??????如果我要使用异步????
}

 私人无效DoAcceptModemCallback(IAsyncResult的AR)
        {
            尝试
            {
                ModemTcpListener.BeginAcceptTcpClient(新的AsyncCallback(DoAcceptModemCallback),ModemTcpListener);
                的TcpClient的TcpClient = ModemTcpListener.EndAcceptTcpClient(AR);
                调制解调器调制解调器=新的调制解调器(TcpClient的,);
                。tcpClient.GetStream()的BeginRead(modem.Buffer,0,tcpClient.ReceiveBufferSize,新的AsyncCallback(DoReadModemCallback),调制解调器);
                ModemTcpListener.BeginAcceptTcpClient(新的AsyncCallback(DoAcceptModemCallback),ModemTcpListener);
                Log.Write(调制解调器连接...);
            }
            赶上(异常前)
            {
            }
        }


解决方案

下面有一个例子跟踪所有的客户端。我已经压缩它的可读性。你真的应该把它分解成多个类。

我使用的游泳池(我刚刚创建和COMMITED)和SimpleServer来。这两个类是我目前正在建设的(但远远没有完成)库的一部分。

不要害怕具有5000插座打开,当您使用异步操作,他们不消耗过多的资源。

 公共类的SuperServer
    {
        私人列表< ClientContext> _clients =新的List< ClientContext>();
        私人SimpleServer来_SERVER;
        私人泳池和LT;字节[]> _bufferPool;        公众的SuperServer()
        {
            //创建一个缓冲池能够重用缓冲区
            //因为你的客户很可能会连接和断开
            //频繁。
            //
            //池需要一个匿名函数,它应该会返回一个新的缓冲区。
            _bufferPool =新池<字节[]>(()=>新建字节[65535]);
        }        公共无效启动(IPEndPoint的ListenAddress)
        {
            _ SERVER =新SimpleServer来(的ListenAddress,OnAcceptedSocket);            //允许五个连接被排队(被接受)
            _server.Start(5);
        }        //你应该处理的BeginSend例外
        //并相应地删除客户端。
        公共无效SendToAll(字节[]信息)
        {
            锁定(_clients)
            {
                的foreach(在_clients VAR客户端)
                    client.Socket.BeginSend(资讯,0,info.Length,SocketFlags.None,NULL,NULL);
            }
        }        //服务器已经接受了新的客户。
        私人无效OnAcceptedSocket(Socket套接字)
        {
            VAR语境=新ClientContext();
            context.Inbuffer = _bufferPool.Dequeue();
            context.Socket =插座;            锁定(_clients)
                _clients.Add(上下文);            //这个方法会吃很少的资源和
            //应具有5000等待插座没有问题。
            context.Socket.BeginReceive(context.Inbuffer,0,context.Inbuffer.Length,SocketFlags.None,OnRead,
                                        背景);
        }        // Woho!已经从客户端之一接收的数据。
        私人无效OnRead(IAsyncResult的AR)
        {
            VAR上下文=(ClientContext)ar.AsyncState;
            尝试
            {
                VAR读取动作= context.Socket.EndReceive(AR);
                如果(读取动作== 0)
                {
                    HandleClientDisconnection(上下文);
                    返回;
                }                //过程context.Inbuffer在这里。
            }
            赶上(例外错误)
            {
                //这里日志例外。
                HandleClientDisconnection(上下文);
                返回;
            }            //使用新的try / catch,以确保我们开始
            //再次读取事件,如果最后的字节处理失败。
            尝试
            {
                context.Socket.BeginReceive(context.Inbuffer,0,context.Inbuffer.Length,SocketFlags.None,OnRead,
                                            背景);
            }
            赶上(例外错误)
            {
                //这里日志例外。
                HandleClientDisconnection(上下文);
            }
        }        //客户端已断开。
        私人无效HandleClientDisconnection(ClientContext上下文)
        {
            _bufferPool.Enqueue(context.Inbuffer);
            尝试
            {
                context.Socket.Close();
                锁定(_clients)
                    _clients.Remove(上下文);
            }
            赶上(例外错误)
            {
                //日志异常
            }
        }
        //你的一个调制解调器
        //添加自己的状态信息。
        私有类ClientContext
        {
            公众的byte [] Inbuffer;
            公共插槽插槽;
        }    }

用于类:

I have around 5000 modem (thin clients), and I want to communicate with them, one of a my method is like this : string GetModemData(modemID), now I have an open port in server that listens to modem and I'm using socket programming to send data to modems (calling related function), but when i want send data to multiple modem in a same time and get response from them, I don't know what should i do? I can send data to one modem and waiting for its response and then send another data to other modems (sequential), but the problem is client should be wait long time to get answer(may be some different client want to get some information from modems so they all will be wait into the Q or something like this), I think one way to solving this problem is to use multiple port and listen for each modem to related port, but it takes too many ports and also may be memory usage going up and exceed my available memory space, so some lost may be occurred (is this true?). what should to do ? I'd thinking about Parallelism, but i think its not related i should to wait for one port, because i don't know should to pass current received data to which client. I'm using asp.net.

currently I'm doing like this:

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

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

and in return

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????
}

and :

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) 
            {
            }
        }

解决方案

Heres an example keeping track of all your clients. I've compacted it for readability. You should really split it up into multiple classes.

I'm using Pool (which I just created and commited) and SimpleServer. Both classes are part of a library that I'm currently building (but far from done).

Don't be afraid of having 5000 sockets open, they do not consume much resources when you are using asynchronous operations.

    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;
        }

    }

Used classes:

这篇关于如何连接使用TCP客户端调制解调器,在多个港口或其他方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆