IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

c# client java server nio2 [Débutant]


Sujet :

C#

  1. #1
    Membre éprouvé
    Homme Profil pro
    Administrateur Systèmes, Clouds et Réseaux /CAO/DAO/Ingénierie Electrotechnique
    Inscrit en
    Décembre 2014
    Messages
    446
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Administrateur Systèmes, Clouds et Réseaux /CAO/DAO/Ingénierie Electrotechnique

    Informations forums :
    Inscription : Décembre 2014
    Messages : 446
    Points : 986
    Points
    986
    Par défaut c# client java server nio2
    Rebonjour.

    Je me suis aperçu avec horreur que mon serveur java en asynchrone (nio2, j'ai pas testé le nio) ne communiquait pas totalement bien avec mon client en c# après avoir vraiment énormément galéré pour comprendre d'ou ça pouvait venir, j'ai a peu près isolé.

    M'étant appuyé sur ce que propose MS sur le site internet et qui avait l'air pas mal, j'ai repris ça pour la réception des données.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
     
           private void ReceiveCallback(IAsyncResult ar)
            {            
                try
                {                
                    // Retrieve the state object and the client socket 
                    // from the asynchronous state object.
                    StateObject state = (StateObject)ar.AsyncState;
                    Socket client = state.workSocket;         
     
                    // Read data from the remote device.
                    int bytesRead = client.EndReceive(ar);
     
                    Console.WriteLine(bytesRead);
     
     
                    /*
                    if (bytesRead > 0)
                    {
                        // There might be more data, so store the data received so far.
                        state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
     
                        // Get the rest of the data.
                        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                            new AsyncCallback(ReceiveCallback), state);
                    }
                    else
                    {
                        // All the data has arrived; put it in response.
                        if (state.sb.Length > 1)
                        {
                            _reponse = state.sb.ToString();
                        }
                        // Signal that all bytes have been received.
                        receiveDone.Set();
                    }
    Le client communique bien vers le serveur mais c'est au retour que survient le soucis. De ce que j'ai compris la méthode beginreceive démarre en fait la réception, chaque appel à Endreceive clos... et donc on choppe au milieu vraisemblablement... Hic, Quand le serveur java a fini de transmettre, lui n'envoie plus rien. Ce qui amène en fait que l'on ne passe jamais dans la partie ou "bytesRead <=0". Donc aussi long que soit le texte, on reste toujours bloqué même si la chaine est bien construite.

    Alors je crois avoir trouvé une solutino de contournement mais j'ai la tête en vrac ... ça a l'air de fonctionner, si quelqu'un a une meilleure solution je suis preneur, peut êtren epas passer par beginreceive ? Mais ça serait toujours asynchrone ?
    Et surtout est ce que tous les cas de figure sont couverts avec l'alternative ou vais je me prendre un mur à un moment ? Ce qui m'inquiète c'est le moment ou une chaine fera pile poil 1024.

    Ce que je ne comprends pas ... il y a peu j'ai travaillé avec des entêtes de trame, il me semble bien que tout envoie indique la longueur... donc en soustrayant la longueur de l'entête on sait d'avance la longueur de la trame... quoique non au final c'est peut être pas une bonne idée. je ne sais plus... Est ce qu'on insère un caractère qui dit qu'on continue l'envoie, d'ordinaire ??? j'ai peut être loupé ça... du coté des algos de java on se contente de lire le buffer jusqu'à la fin en fait.

    Bref ma solution pour le moment, mais je la sens boiteuse.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
     
                    if (bytesRead >= state.buffer.Length)
                    {
     
                        // There might be more data, so store the data received so far.
                        state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
     
                        // Get the rest of the data.
                        client.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
                    }
                    else if ( bytesRead < state.buffer.Length )
                    {
                        state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
                        _reponse = state.sb.ToString();
                        receiveDone.Set();
                    }
                    else if (bytesRead <=0)
                    {
                        // All the data has arrived; put it in res
                        if (state.sb.Length > 1)
                        {
                            _reponse = state.sb.ToString();
                        }
                        // Signal that all bytes have been received.
                        receiveDone.Set();
                    }
    Merci d'avance.

  2. #2
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 150
    Points : 25 066
    Points
    25 066
    Par défaut
    je pensais en avoir écrit des mieux mais j'ai retrouvé que celui là :
    https://www.developpez.net/forums/d1...p/#post8178515

    après j'ai pas lu tout code mais avec un peu de chance c'est lié

    dans le principe quand on dialogue on prévoit une norme, soit début/fin de trame, soit entête qui précise la longueur de la trame (comme en http par exemple), donc on attend une entete complète pour ensuite trouver un message entier
    mais tout est toujours à conserver et à "concaténer"
    avec un buffer de x ko, on demande à lire x ko, quand des octets arrivent ton buffer contient les données et tu connais le nombre d'octets reçus, et donc quelle partie du buffer contient des données (le reste du buffer contient des 0 à ne pas utiliser)
    puis tu redemandes à lire x ko dans ton buffer
    et ton buffer alimente un buffer plus gros
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    Membre éprouvé
    Homme Profil pro
    Administrateur Systèmes, Clouds et Réseaux /CAO/DAO/Ingénierie Electrotechnique
    Inscrit en
    Décembre 2014
    Messages
    446
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Administrateur Systèmes, Clouds et Réseaux /CAO/DAO/Ingénierie Electrotechnique

    Informations forums :
    Inscription : Décembre 2014
    Messages : 446
    Points : 986
    Points
    986
    Par défaut
    J'ai lu mais même en contournant le soucis pour le moment je retrouve toujours le mêem soucis.

    Le dernier truc en date c'est que je mets le séparateur en byte 0x04, lorsqu'il est détecté par le client il sépare au lieu de compter les bytesread communiqué par endreceive. Là en effet ça plante pas... mais c'est aux alentours de la taille de buffer que les problèmes réapparaissent toujorus dans un sens ou l'autre. Je vais implémenter du coté serveur ce même mot séparateur, car pour le moment en fait je me contentais de l'injecter aux alentours de la taille du buffer.. mais ça collera jamais.

    Pour ce qui est inversement d'annoncer la taille, ça me paraissait pas mal mais je cale sur un point... a moins de la passer en clair dans le message comment faire ?? je peux pas dire que je réserve X bytes ? vu que bytes ici c'est des codes de caractères. au final... a moins de recomposer ma taille en spécifiant sur plusieurs bytes ? 2 suffiraient ?

    J'aurais bien aimé savoir ce qui se passait sous beginreceive car après avoir fait des dizaines de test il apparait que lorsque le client demande plus, il n'y a pas besoin de séparateur, on ne lui renvoie rien et d'ailleurs renvoyer est un bien grand mot j'ai vu aucune trace en mettant des Console.Writeline du coté du serveur... peut être mettre des points d'arrêt pour voir mais ça me changera pas grand chose si c'est transparent. J'ai voulu envoyer des bytes vides avec le serveur java, ça ne fait rien du coté c# client, y'a vraiment que le délimiteur qui pourrait changer qq chose. J'ai lu en passant, dans les commentaires en anglais qu'apparemment une méthode comme begin receive n'existe pas sous java... alors au pire peut être changer de langage mais quoi sous linux en asynchrone ? Galère !!!!

    Merci, au fait.. !


    Edit
    Bon j'ai réussi, je mets la résolution ici, après y'a peut être moyen de faire mieux surtout au niveau de la concaténation de chaines. Le code se base donc sur https://msdn.microsoft.com/fr-fr/lib...v=vs.110).aspx
    Il y a des choses modifiées, je ne mets que les parties concernées pour ne pas en mettre deux tonnes, d'autant que c'est coupé dans tous les sens etc pour correspondre à ce que je veux faire.

    Modification du send pour qu'il envoie systématiquement le byte 4 à la fin de toute communication.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
            #region emission
            private void Send( String data)
            {
                Socket client = _sClient;
                // Convert the string data to byte data using ASCII encoding.
                //byte[] byteData = Encoding.ASCII.GetBytes(data);
     
                byte[] fin = { 4 };
                byte[] datab = Encoding.ASCII.GetBytes(data);
     
                byte[] byteData = new byte[datab.Length + fin.Length];
     
                datab.CopyTo(byteData, 0);
                fin.CopyTo(byteData, datab.Length);
     
     
                // Begin sending the data to the remote device.
                client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);
            }
    Là ou byteData était une conversion de chaine en byte, maintenant c'est une concaténation de deux arrays (et j'aimerai bien simplifier), pour rajouter le délimiteur à la fin (ici ça sera EOT, donc 4 )



    Au niveau du code du serveur java simplifié fonctionnant en echo, basé sur un asynchronousserversocketchannel fonctionnant pour le moment en mode "Future" afin que ça soit plus simple, l'interception est faite aussi sur le byte.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    				  while ( client.read(TAMPON).get() != -1 ) 
    				  {
    					  TAMPON.flip();
     
    					  // Pour faire plus lisible transfert dans un byte du contenu du ByteBuffer
    					  byte k = 4;					  
    					  byte[] byteArr = new byte[TAMPON.remaining()];					  
    					  TAMPON.get( byteArr);
     
    					  // Check si correspondance byte à byte
    					  for(int i=0; i< TAMPON.limit(); i++) {
    						  if ( byteArr[i] == k ) {
    							  System.out.println("ok");
    							  break;
    						  }
    					  }
    					 // Fin du check
     
    					  // Afficher contenu du bytebuffer
    					  Charset charset = Charset.forName("ISO-8859-1");
    					  String v = charset.decode( TAMPON ).toString();
    					  System.out.println("contenu du buffer: " + v);
    					  // Afficher contenu du bytebuffer
     
    					  TAMPON.flip();				//
    					  client.write(TAMPON).get();
     
     
    					  if (TAMPON.hasRemaining()) {
    						  System.out.println("remain");
    						  TAMPON.compact();
    					  } else {
    						  System.out.println("pasremain");
     
    						  TAMPON.clear();
    					  }
     
    					  System.out.println(client.getRemoteAddress() +
    							  " was successfully served!");
    					  System.out.println("finboucle");
    				  }

    Enfin dans le client C# quand on passe par le callback on ne passe plus donc par bytesRead > 1 ou quelque chose du genre... mais sur le séparateur.
    Je refactoriserai mais là c'est plus facile à lire.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
                    byte k = 4;
                    int res = Array.IndexOf(state.buffer, k);
     
                    if (res > -1)       // Il y a une fin
                    {
     
                        state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead-1));
     
                        if (state.sb.Length >= 1)
                        {
                            _reponse = state.sb.ToString();
                        }
                        receiveDone.Set();
     
                    }
                    else if( res == -1)     // Pas encore la fin donc on "reboucle"
                    {
     
                        state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
                        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
     
                    }

    Si quelqu'un a une meilleure approche je suis preneur, surtout pour rendre réellement compatible java avec c#... J'ai testé le code avec des messages de diverses longueurs via "string messagetest = new String('c', x);" apparemment pas de bug... sous réserve de passer un message mais pour le moment je ne pense pas passer un message de 0 caractère. La récupération de la chaine est identique pour peu qu'on mette de coté les accents..

    Et j'ai mal au crane ^^ !

    Je me suis pas mal interrogé donc sur l'idée de continuer ainsi, j'ai vu qu'on pouvait faire du rpc avec c# comme java... mais est ce que c'est possible de le faire pour un client c# .net (framework etc) avec un serveur sous mono ? voire .net Core (mais est ce que .net Core vaut le coup sous ubuntu ? ) . J'ai pourtant énormément réfléchis dès le départ, mais c'est franchement pas évident avec des machines sous os différents.

  4. #4
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 150
    Points : 25 066
    Points
    25 066
    Par défaut
    pour la taille en octets, oui le principe c'est de réserver x octets pour définir la taille (avec 2 ou 4 octets ou autre)
    bitconverter permet de transformer un type de base en tableau de bytes ou l'inverse

    beginreceive n'est qu'un artifice pour faciliter (dans certains cas), ca utilise receive derrière à priori (mais sur un autre thread)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  5. #5
    Membre éprouvé
    Homme Profil pro
    Administrateur Systèmes, Clouds et Réseaux /CAO/DAO/Ingénierie Electrotechnique
    Inscrit en
    Décembre 2014
    Messages
    446
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Administrateur Systèmes, Clouds et Réseaux /CAO/DAO/Ingénierie Electrotechnique

    Informations forums :
    Inscription : Décembre 2014
    Messages : 446
    Points : 986
    Points
    986
    Par défaut
    Tu validerais mon algorithme ? Ca a l'air correct ?

    Sinon sincèrement, tant pis si je suis déçu, tu penses que c'est viable de poursuivre cette idée de serveur java, avec client c# ... je suis en trian de me demander si c'est pas contreproductif au final, j'avais lu les benchmarks avec différents langages pourtant... . Là , j'ai vite reporté le code du serveur c# de test sous mono, vu que le serveur est purement console, et le restera. Ca tourne sous ubuntu, sans rien avoir à faire... j'avais opté pour java pour la portabilité, pour parait il sa solidité sur les serveurs. Est ce que ça vaut le coup au final... ou est ce que je vais prendre d'autres murs du même genre ? Pour faire transiter les données je pensais faire du xml que j'aurais converti en binaire... Et pour les commandes, rien de compliqué quelque chose du genre Cmd=un numero, et derrière les arguments dans une sorte de dico... Et de faire traiter derrière par un thread. J'ai un peu lu ce qu'était le RPC sous c# et le RMi sous java... ça passe par des protocoles normalisés au final, non ? C'est facile car déjà mis en place, mais quoi de plus sinon ? Enfin c'est déjà un argument pour une homogénéité serveur, client... Je ne sais plus d'ailleurs si mono gère le rpc.

    Merci en tout cas.

  6. #6
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 150
    Points : 25 066
    Points
    25 066
    Par défaut
    pas lu le code non, j'aurais ptete le temps demain

    par contre si wcf existe sur mono ca t'éviterait de t'embêter avec cette couche de comm

    (dans le principe tu appelles une méthode/fonction côté client wcf envoie ça au serveur qui exécute la méthode/fonction côté serveur et te retourne le résultat
    wcf s'est donc occupé de toute la partie communication et tu as des appels transparents à des méthodes qui sont sur le serveurs tout en ayant l'IntelliSense côté client)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  7. #7
    Membre éprouvé
    Homme Profil pro
    Administrateur Systèmes, Clouds et Réseaux /CAO/DAO/Ingénierie Electrotechnique
    Inscrit en
    Décembre 2014
    Messages
    446
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Administrateur Systèmes, Clouds et Réseaux /CAO/DAO/Ingénierie Electrotechnique

    Informations forums :
    Inscription : Décembre 2014
    Messages : 446
    Points : 986
    Points
    986
    Par défaut
    Le code est obsolète au final, ne te casse pas la tête.
    J'ai commencé par opter pour c# des deux cotés. Après j'ai réussi à comprendre ou positionner une boucle pour être en connexion persistante, et je suis en train de tout repositionner de manière différente et gestion des commandes. Y'a juste une chose que j'ai du mal à capter c'est une sorte d'écrasement du tampon sur des envois avec des temps de latence très courte. Apparemment avec 1ms de temps de latence (ok qu'est ce qui m'a pris de faire ça) le tampon n'arrive plus à se vider assez pour ne pas arriver à un plantage, mais je voulais voir coté sécurité quoi implanter, à voir pour plus tard au final... J'ai dans l'idée de simplement fermer le socket sur des requêtes trop rapprochées.

    Edit m'est venu la nécessite de passer des petits fichiers, j'espère ne pas avoir fait d'erreur. Via une commande j'ouvre un serveur éphémère via un thread en asynchrone, je lui passe la fonction pour renvoyer des infos via un délégué afin qu'il renvoie le port sur lequel il s'ouvre au "client" qui en fait la demande. Il possède un timeout pour éviter que ça soit ouvert aux 4 vents. Je sais pas si on fait comme ça d'habitude... Ca a l'air rapide en tout cas, la réponse est renvoyée en moins d'1s et ça ne fige pas du coup la boucle qui rafraichit le tout étant donné que les commandes passent par ce même socket. J'ai essayé d'envoyer le fichier mais du coup ça bloquait les rafraichissements, donc quand la boiboite se fermait pour choisir le fichier ça ne figeait pas puisque c'est commandé par un thread asynchrone mais plus de rafraichissements. Ca fait bizarre de programmer ainsi.Pour le moment les retours sont récupérer directement mais je me demande si un genre de dictionnaire ne serait pas plus judicieux, de sorte que la valeur de retour aille dans la case dans son dictionnaire. Là ça n'arrive pas car le réseau est très rapide mais en théorie si je ne me plante pas, des valeurs de retour pourraient se chevaucher... il y a un handler coté serveur pour gérer les commandes mais pas coté client pour les retours de commande, ça prend la commande comme elle vient.

    J'imaginais pas que c'eétait si chaud le réseau.

    Merci.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 12/04/2012, 11h16
  2. [VB6] Reseau LAN: Server VB6, Client Java.
    Par remya dans le forum VB 6 et antérieur
    Réponses: 11
    Dernier message: 27/12/2010, 23h22
  3. Connexion Java(server) et Python(client)
    Par xeerox23 dans le forum CORBA
    Réponses: 1
    Dernier message: 01/12/2009, 18h22
  4. [WebService]Server Delphi et client Java
    Par davels dans le forum Web & réseau
    Réponses: 12
    Dernier message: 05/06/2008, 12h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo