2010-10-27 12 views
1

J'ai environ 5000 modem (clients légers), et je veux communiquer avec eux, un de ma méthode est comme ceci: string GetModemData(modemID), maintenant j'ai un port ouvert dans le serveur qui écoute le modem et j'utilise la programmation socket pour envoyer des données aux modems (appelant la fonction connexe), mais quand je veux envoyer des données à plusieurs modem en même temps et obtenir une réponse de leur part, je ne sais pas ce que je devrais faire? Je peux envoyer des données à un modem et attendre sa réponse, puis envoyer une autre donnée à d'autres modems (séquentiel), mais le problème est que le client attendrait longtemps pour obtenir la réponse (peut être un client différent veut obtenir des informations des modems donc ils seront tous attendre dans le Q ou quelque chose comme ça), je pense qu'une façon de résoudre ce problème est d'utiliser plusieurs ports et d'écouter chaque modem sur le port correspondant, mais cela prend trop de ports et peut aussi utiliser la mémoire et dépasse mon espace mémoire disponible, donc certains peuvent être perdus (est-ce vrai?). que devrait-on faire? Je pensais au parallélisme, mais je pense que ce n'est pas lié je devrais attendre un port, parce que je ne sais pas devrait transmettre les données reçues à quel client. J'utilise asp.net.Comment se connecter à des modems avec des clients tcp, sur plusieurs ports ou d'une autre manière?

actuellement je fais comme ceci:

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

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

et en retour

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

et:

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

Que faites-vous dans le DoAcceptModemCallback? –

+0

Maintenant, ce que vous devriez faire est de garder une référence à l'objet modem dans une liste, mais vous avez toujours le problème d'identifier les modems, l'application de modem est-elle à vous, je veux dire avez-vous écrit cette application? Parce que si vous le faites, vous devriez laisser le modem vous envoyer une identification quand il se connecte au serveur. –

+0

@A_Nablsi, Modem est ma classe, je peux les suivre, mais chez les clients j'ai un problème (pas de clients légers, les modems sont des clients légers) j'ai trouvé une solution mais c'est compliqué, car je vais faire trop d'algorithmes d'analyse pour trouver un moyen simple, maintenant je vais trop dormir: D –

Répondre

2

Heres un exemple garder une trace de tous vos clients. Je l'ai compacté pour la lisibilité. Vous devriez vraiment le diviser en plusieurs classes. J'utilise Pool (que je viens de créer et commited) et SimpleServer. Les deux classes font partie d'une bibliothèque que je suis en train de construire (mais loin d'être terminée). N'ayez pas peur d'avoir 5000 sockets ouvertes, elles ne consomment pas beaucoup de ressources lorsque vous utilisez des opérations asynchrones.

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

    } 

cours d'occasion:

+0

merci je vais les voir, maintenant je vais dormir: D –

1

Vous devez utiliser les méthodes asynchrones tcp/ip. Cet article montre comment:

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

La pièce critique est le BeginReceive() et les fonctions de rappel connexes. Plus de q, s'il vous plaît laissez des commentaires à cette réponse;) BEST OF LUCK!

+0

En outre, je vous suggère de conserver un tableau de connexions ouvertes, par exemple Socket [] = new Socket [5000]; Si vous utilisez les appels asynchrones, l'utilisation du port et la mémoire ne devraient pas poser de problème, car le traitement ne se fera que sur une connexion ouverte, commencer à recevoir et quand des données sont reçues (rappel de fonction). – vdoogs

+0

Cet article contient plusieurs failles qui peuvent faire planter l'application ou se comporter de manière inattendue. Cela peut fonctionner correctement avec une ou deux prises connectées. Ne mélangez jamais les threads et la méthode asynchrone comme il le fait dans l'article. Et ne jamais vérifier un événement pour null et ensuite l'invoquer, l'événement peut avoir été effacé entre les deux. Ne mangez pas d'exceptions avec des blocs de prises vides. – jgauffin

+0

@jgauffin, je suis d'accord avec vous, mais vdoogs ouverture trop de socket ne résout pas mon problème, je devrais écouter aussi quel modem dans quelle socket? peut être je ne peux pas dire avec soin mon problème s'il vous plaît voir mon commentaire sur A_Nablsi. –

1

Vous avez besoin d'un multi-threading, chaque fois qu'un client établit une connexion avec le serveur, lancez un nouveau thread et démarrez la communication envoyer/recevoir.

Voici quelques articles expliquant multithreading C#, c-sharpcorner codeproject

Et voici une application de serveur exemple avec multithreading, http://www.dotnetspider.com/resources/2829-A-multi-readed-server-C-which-finds-prime-num.aspx

+0

pensez à ce scénario: vous avez 5 clients différents, ils veulent récupérer 5 données de clients légers différents, s'ils écoutent sur un seul port comment je peux trouver des données sorcières reçues pour que le client sorcier le passe? si je me connectais aux clients avec tcp ip ou comme ça, je peux enregistrer leur adresse IP (MAC ou ...) et leur renvoyer des données, mais j'utilise asp.net juste un appel de fonction et je ne sais pas envoyer les données reçues à quel client. parce que je ne suis pas un maître IIS le fera. –

+0

Je ne créerais pas un nouveau thread pour chaque client, c'est un moyen très inefficace. Utilisez des E/S asynchrones à la place (BeginRead/EndRead, etc.). – jgauffin

+0

S'il vous plaît j'ai besoin de plus d'explications Je ne peux pas imaginer comment garder les connexions avec les clients sur le serveur et je ne suis pas sûr si vous établissez une connexion du serveur aux clients quand vous voulez obtenir leurs données. Votre application comme j'imagine chaque fois qu'un client établit une connexion au serveur doit garder une référence à l'objet socket du client et par cela vous pouvez communiquer avec tous les clients que vous gardez les références de leurs objets socket asychnronously ou par multithreading. –