Как подключиться к модемам с помощью tcp-клиентов, несколькими портами или другим способом? - PullRequest
1 голос
/ 27 октября 2010

У меня около 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 ]

2 голосов
/ 27 октября 2010

Вот пример отслеживания всех ваших клиентов.Я сжал это для удобочитаемости.Вы действительно должны разделить его на несколько классов.

Я использую 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 голос
/ 27 октября 2010

Вам нужна многопоточность, когда клиент устанавливает соединение с сервером, запускайте для него новый поток и начинайте отправку / получение связи.

Вот несколько статей, объясняющих многопоточность в c #, c-sharpcorner код проекта

А вот пример серверного приложения с многопоточностью, http://www.dotnetspider.com/resources/2829-A-multi-readed-server-C-which-finds-prime-num.aspx

1 голос
/ 27 октября 2010

Вам необходимо использовать асинхронные методы tcp / ip. Эта статья показывает, как:

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

Критическим элементом является BeginReceive () и связанные функции обратного вызова. Еще вопросы, пожалуйста, оставляйте комментарии к этому ответу;) УДАЧИ!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...