2010-10-27 82 views
1

我有大約5000個調制解調器(瘦客戶端),我想與他們溝通,我的方法之一是這樣的:string GetModemData(modemID),現在我有一個開放的服務器端口監聽調制解調器,我使用套接字編程發送數據到調制解調器(調用相關功能),但是當我想要在同一時間內向多個調制解調器發送數據並獲得響應時,我不知道該怎麼辦?我可以發送數據到一個調制解調器並等待它的響應,然後發送另一個數據到其他調制解調器(順序),但問題是客戶端應該等待很長時間才能得到答案(可能是某些不同的客戶端想從調制解調器獲取某些信息所以他們都會等待Q或類似的東西),我認爲解決這個問題的一種方法是使用多個端口,並監聽每個調制解調器到相關的端口,但它佔用太多的端口,也可能是內存使用量超出我的可用內存空間,所以可能會發生一些丟失(這是真的嗎?)。該怎麼辦?我會考慮Parallelism,但我認爲它不相關,我應該等待一個端口,因爲我不知道應該將當前接收的數據傳遞給哪個客戶端。我正在使用asp.net。如何使用多個端口或其他方式連接到具有tcp客戶端的調制解調器?

目前我在做這樣的:

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

你怎麼在DoAcceptModemCallback嗎? – 2010-10-27 18:51:08

+0

現在你應該做的是保持列表中的調制解調器對象的引用,但你仍然有識別調制解調器的問題,調制解調器應用程序是你的,我的意思是你寫了那個應用程序?如果你這麼做,那麼你應該讓調制解調器在連接到服務器時向你發送一個標識。 – 2010-10-27 19:11:58

+0

@A_Nablsi,Modem是我的班級,我可以跟蹤他們,但在客戶端我有一個問題(不是瘦客戶端,調制解調器是瘦客戶端)我找到了一個解決方案,但它的複雜,因爲我會做太多的解析算法,我想找一個簡單的方法,現在我要去睡覺了:D – 2010-10-27 19:53:39

回答

2

這裏有一個例子跟蹤所有的客戶端。爲了可讀性,我壓縮了它。你應該真的把它分成多個類。

我使用池(我剛剛創建並提交)和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; 
     } 

    } 

使用的類:

+0

謝謝,我會看到他們,現在我要睡覺了:D – 2010-10-27 19:49:19

1

您需要使用異步TCP/IP的方法。本文將介紹如何:

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

的關鍵部分是BeginReceive()和相關的回調函數。還有更多的問題,請給這個答案留下評論;)最好的運氣!

+0

此外,我建議你保持一個開放的連接數組,例如Socket [] = new Socket [5000];如果使用異步調用端口,則使用和內存不應該成爲問題,因爲處理將僅在打開的連接上發生,開始接收以及接收數據時(函數回調)。 – vdoogs 2010-10-27 18:18:22

+0

該文章包含一些可能導致應用程序崩潰或意外行爲的缺陷。它可以在一個或兩個連接的套接字上正常工作。不要像在文章中那樣混合使用線程和異步方法。並且從不檢查一個事件爲null,然後調用它,事件可能已被清除。不要用空的catch塊來吃異常。 – jgauffin 2010-10-27 18:32:44

+0

@jgauffin,我同意你的看法,但是vdoogs打開太多的socket並不能解決我的問題,我應該聽哪個調制解調器在哪個socket?可能是我不能仔細說出我的問題,請看我對A_Nablsi的評論。 – 2010-10-27 18:37:28

1

只要客戶端建立到服務器的連接,就需要多線程,爲它啓動一個新線程並啓動通信發送/接收。

這裏有一些文章解釋在C#中的多線程, c-sharpcorner codeproject

而這裏的多線程樣本服務器應用程序, http://www.dotnetspider.com/resources/2829-A-multi-readed-server-C-which-finds-prime-num.aspx

+0

想想這種情況:你有5個不同的客戶端,他們想獲取5個不同的瘦客戶端數據,如果他們在單個端口上收聽,我怎麼能找到巫婆客戶端接收到的巫婆數據以通過它?如果我連接到客戶端與TCP IP或像這樣我可以保存他們的IP地址(MAC或...)併發回數據給他們,但我使用asp.net只是一些函數調用,我不知道發送收到的數據給客戶端。因爲我不是主人,IIS將會這樣做。 – 2010-10-27 18:25:25

+0

我不會爲每個客戶創建一個新線程,這是一個非常低效的方式。改用異步IO(BeginRead/EndRead等)。 – jgauffin 2010-10-27 18:27:57

+0

請問我需要更多解釋我無法想象你如何保持與客戶端在服務器上的連接,並且我不確定當你想獲取他們的數據時,是否建立了從服務器到客戶端的連接。當我想象客戶端建立與服務器的連接時,您的應用程序必須保持對客戶端套接字對象的引用,通過這種方式,您可以與所有客戶端保持通信,或者通過多線程來保持其套接字對象的引用。 – 2010-10-27 18:43:55

相關問題