如何使用tcp客户端,多端口或其他方式连接到调制解调器?

时间:2010-10-27 18:06:14

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

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

答案 0 :(得分:2)

以下是跟踪所有客户的示例。为了便于阅读,我已经压缩了它。你应该把它分成多个类。

我正在使用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;
        }

    }

使用过的课程:

答案 1 :(得分:1)

您需要使用异步tcp / ip方法。本文将介绍如何:

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

关键部分是BeginReceive()和相关的回调函数。还有q,请在这个答案留下评论;)最好的运气!

答案 2 :(得分:1)

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

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

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