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

Windows Forms Discussion :

[C#] Client/serveur avec port série


Sujet :

Windows Forms

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 58
    Points : 34
    Points
    34
    Par défaut [C#] Client/serveur avec port série
    Bonjour,

    J'ai une application cliente que je voudrais faire communiquer avec une application serveur (située sur un autre poste) via le port série (COM1). Je ne sais pas trop comment m'y prendre. Pour l'instant, à part avoir créer un port série sur chaque application et les avoir paramétrer de la même façon, je bloque un peu sur la façon de pouvoir envoyer/lire des données d'une application vers l'autre (à part faire le OpenPort() au début de la requête puis le ClosePort() à la fin, je sais pas trop quoi mettre entre pour pouvoir envoyer/lire des données du client vers le serveur et vice-versa).

    De plus, quand on communique via le port série, comment dire à l'appli qu'on veut utiliser le protocole modbus? (je suis nul en réseau, et à part le fait qu'il s'agit apparemment d'un protocole qui décrit le format des données à émettre/recevoir, je vois pas trop à quoi il sert...)

    Merci par avance à ceux qui pourront éclairer un peu mon chemin (et ceux qui essaieront)

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    238
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 238
    Points : 269
    Points
    269
    Par défaut
    Salut, je suis en train de developper un soft qui utilise ModBus aussi en serie aussi.
    Modbus est un protocol qui permet de comprendre quelles sont les trames envoyer, la signification des différents champs. IL faut que tu te rensigne la dessus, l'entreprise dans laquelle tu ai a forcement de la documentation la dessus.

    Pour la communication serie, je me suis inspirer de ca :
    http://www.codeproject.com/csharp/Se...munication.asp
    c'est nikel !

    Bonne chance
    « L’erreur est humaine, mais un vrai désastre nécessite un ordinateur »

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 58
    Points : 34
    Points
    34
    Par défaut
    Tout d'abord, merci pour ta réponse.

    Niveau modbus, j'ai bien de la doc dessus, et donc vu comment ça fonctionnait pour le format des trames, etc.

    Pour le read/write ça fonctionne lorsque je le fais à partir de la même appli depuis une textBox. Le véritable problème est que je ne vois pas comment dire à mon client: "Connecte toi à l'appli serveur" (qui est sur une autre machine) pour pouvoir ensuite envoyer mes data vers cette appli (et vice-versa).

  4. #4
    Membre actif
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    238
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 238
    Points : 269
    Points
    269
    Par défaut
    Que tu sois sur la même machine ou pas c'est pareil, il faut juste que tu ai un cable croisé entre les deux ports.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    private void OuvertureDuPort()
    {
         try
         {
               _Port = new SerialPort(_PortName, _BaudRate, _parity, _nb_Bits_Char, _stopBits);
                _Port.Open();
          }
           catch (IOException ioex)
           {
                ......   
            }            
    }
    Si de l'autre coté, un ecouteur est en place et que la config est la même (baud rate, parity...) ca va marcher.

    Si tu arrives à le faire marcher sur ta machine c'est bon ca tournera en réseau. La communication Serie, c'est pas TCP/IP, y a pas a se prendre la tete c'est très facile.
    « L’erreur est humaine, mais un vrai désastre nécessite un ordinateur »

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 58
    Points : 34
    Points
    34
    Par défaut
    Ben le problème, c'est que j'ai bien ouvert le port série des 2 côtés (même config) mais j'arrive pas à faire un écouteur côté serveur

  6. #6
    Membre actif
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    238
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 238
    Points : 269
    Points
    269
    Par défaut
    ... Tu fait la même chose
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MonSerialPort.Read(Buffer, 0,20)
    Ca va mettre ton serveur en attente d'une connection, une fois que quelqu'un va se connecter il pourra envoyer son message.
    Attention, il faut penser à utiliser les threads si nécessaire.
    « L’erreur est humaine, mais un vrai désastre nécessite un ordinateur »

  7. #7
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 58
    Points : 34
    Points
    34
    Par défaut
    Voilà le code côté client.
    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
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
     
    /// <summary>
    /// Port de communication modbus série côté client (Master).
    /// </summary>
    private SerialPort clientModbusPort = new SerialPort();
     
    //Configuration du port suivant le choix de l'utilisateur
    //je passe volontairement cette fonction => clientModbusPort.baudRate = ... 
     
    /// <summary>
    /// Constructeur.
    /// </summary>
    public FormClientModbus()
    {
    //Initialise les composants du formulaire.
    InitializeComponent();
     
    //Initialisation des composants nécessaires à la configuration de la communication entre l'application cliente et l'application serveur.
    InitializeConfiguration();
     
    //Evènement de réception de données sur le port série.
    clientModbusPort.DataReceived+=new SerialDataReceivedEventHandler(clientModbusPort_DataReceived);
    }
     
    /// <summary>
    /// Méthode appelée lorsqu'il y a des données dans le buffer du port série
    /// de l'application cliente.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void clientModbusPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
    //Nombre de bytes à lire dans le buffer du port.
    int bytesToRead = clientModbusPort.BytesToRead;
     
    //Tableau de stockage des bytes du buffer de lecture.
    byte[] clientReceiveBuffer = new byte[bytesToRead];
     
    //Lit les données du buffer et les stocke dans le tableau prévu à cet effet.
    clientModbusPort.Read(clientReceiveBuffer, 0, bytesToRead);
    }
     
    /// <summary>
    /// - Ouvre un port de communication série selon les paramètres sélectionnés
    ///par l'utilisateur.
    /// - Effectue la requête demandée par l'utilisateur.
    /// - Ferme le port de communication série.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void buttonRequeteSendRequest_Click(object sender, EventArgs e)
    {
      if (slaveAddress)
      {
        //Ouvre un port de communication série avec les paramètres définis par
        //l'utilisateur.
        Configuration_SelectedParameters();
     
        try
        {
        clientModbusPort.Open();
        }
        catch (Exception openPortException)
        {
          MessageBox.Show("An exception occurs :\r\n" +
          openPortException.StackTrace + "\r\n\r\nDetails :\r\n" +
          openPortException.Message, Application.ProductName, 
          MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
     
        //Envoie le numéro esclave à l'application serveur (device slave).
        //--<Mettre ici l'envoi du numéro esclave au serveur>--
     
        //Effectue la requête.
     
     
        //Ferme le port de communication série.
        try
        {
          clientModbusPort.Close();
        }
        catch (Exception closePortException)
        {
          MessageBox.Show("An exception occurs :\r\n" + 
          closePortException.StackTrace + "\r\n\r\nDetails :\r\n" + 
          closePortException.Message, Application.ProductName, 
          MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
      }
      else
      {
        MessageBox.Show("Le numéro esclave doit être compris entre 1 et 31
        .", "Numéro esclave invalide !", MessageBoxButtons.OK, 
        MessageBoxIcon.Error);
      }
    }
    J'ai fait la même chose côté serveur (variable SerialPort serveurModbusPort) et avec la même configuration (baudRate, parity, timeout) + ce bout de code:
    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
     
    /// <summary>
    /// Démarre le serveur.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void buttonServeurModbusLecture_Click(object sender, EventArgs e)
    {
      if (serverState)
      {
        //Le serveur est déjà démarré.
        MessageBox.Show("Le serveur est déjà démarré.", "Attention !",
        MessageBoxButtons.OK, MessageBoxIcon.Warning);
      }
      else
      {
        //Ouvre un port de communication série avec les paramètres définis par
        //l'utilisateur.
        Configuration_SelectedParameters();
     
        serveurModbusPort.Open();
        serveurModbusPort.WriteLine("mouarf");
        //Serveur démarré.
        serverState = true;
        textBoxServeurModbusEtat.Text = serverStateOn;
      }
    }
    Quand je clique sur le bouton "lecture", je démarre le serveur. Puis quand je vais coté client (pour l'instant je teste les 2 applis sur la même machine) et que je clique sur le bouton "send request", j'obtiens l'erreur suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    An exception occurs:
      at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
      at ........
    Details:
      Access to the port 'COM1' is denied.

  8. #8
    Membre actif
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    238
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 238
    Points : 269
    Points
    269
    Par défaut
    Il faut configurer le port pour tes deux appli, par defaut c'est le Com1.
    Puisque tu as deja une pli qui tourne sur le COM1 l'acces est interdit pour la seconde appli d'où le message d'erreur.
    Il te faut définir un port pour l'appli 1 COM1, et un pour l'appli 2 COM2 et relier ces deux ports par un cable croisé.

    Deux appli ne peuvent pas occuper la même resource en même temps c'est normale. Sinon tu fait entre deux machines et ca marchera !
    « L’erreur est humaine, mais un vrai désastre nécessite un ordinateur »

  9. #9
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 58
    Points : 34
    Points
    34
    Par défaut
    Ok merci pour l'erreur déjà Je vais voir si je trouve un moyen de faire cet écouteur côté serveur.

  10. #10
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 58
    Points : 34
    Points
    34
    Par défaut
    J'arrive enfin à envoyer des trames (codage ASCII ou BigEndianUnicode) entre le client et le serveur. Cependant, j'arrive toujours pas à comprendre comment on peut dire qu'on va utiliser le protocole modbus sur la liaison série aux 2 applis (et donc implémenter en conséquence les fonctions modbus dont on a besoin = lecture/écriture + éventuellement diagnostics et autres).

  11. #11
    Membre actif
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    238
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 238
    Points : 269
    Points
    269
    Par défaut
    C'est à toi de l'implémenter, tu crois pas que tu va donner le protocole et que le SerialPort va faire tout le travail lol.
    Il faut construire tes trames Octet par Octet

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Byte[] MaTrame = new Byte[6];
    MaTrame[0] = 0x11;
    MaTrame[1] = Ox01;
    ...
    Remplir les champs correctement selon les informations du protocole pour que tu puisse être compris. De l'autre coté, il te faut analyser les trames et répondre en conséquence. Si tu respectes pas bien le protocole, ton appli sera inutil puisque personne ne pourra te comprendre, donc buche bien sur celui-ci pour le comprendre et l'utiliser correctement.
    C'est un protocole très basic, il y à pas trop de feinte et d'exception donc relativement facile à maîtriser.

    Il faut maitriser les écritures Hexadécimal, et les conversion. Pour ca tu peux utiliser la méthode Convert.ToByte().

    Je te post des méthodes que j'utilise pour travailler dessus les deux premières c'est pour récupérer les poids fort et poid faible des entiers, et les deux autres c'est pour transformer la Trame en String, pour l'affichage et le contrôle de ce que tu envoies.

    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
     
     
    //Permet de récupérer le Poid Faible
    public Byte LOWBYTE(int valeur)
    {
          if (valeur < 255) return Convert.ToByte(valeur);  // Cas sur un Octect
          else return Convert.ToByte(valeur & 0x00FF);      // Cas ou il faut l'octect Faible
    }
     
    //Permet de récupérer le Poid Fort
    public Byte HIGHTBYTE(int valeur)
    {
         if (valeur < 255) return 0;
         else return Convert.ToByte(valeur >> 8);
    }
     
    //Permet de transformer la Trame en chaine de caractères
    public String TrameToString(Byte[] pTrame)
    {
         String TrameFormatString = "";
         for (int i = 0; i < pTrame.Length; i++)
         {
                TrameFormatString += ToHexString(pTrame[i]);
                if (i != (pTrame.Length - 1)) TrameFormatString += " ";
          }
     
           return TrameFormatString;
    }
     
    private String ToHexString(byte byte1)
    {
         return byte1.ToString("X2", null);
    }

    Ca devrait pas mal t'aider.
    « L’erreur est humaine, mais un vrai désastre nécessite un ordinateur »

  12. #12
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 58
    Points : 34
    Points
    34
    Par défaut
    Je pensais qu'il suffisait de configurer chaque port série pour pouvoir utiliser le protocole en mode ASCII/RTU. Du style :
    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
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
     
    //PortName
    serveurModbusPort.PortName = comboBoxConfigurationPortCOM.SelectedItem.ToString();
     
    //BaudRate
    serveurModbusPort.BaudRate = int.Parse(comboBoxConfigurationVitesse.SelectedItem.ToString());
     
    //Parity
    switch (comboBoxConfigurationParite.SelectedItem.ToString())
    {
      case "Aucune":
        serveurModbusPort.Parity = Parity.None;
        serveurModbusPort.StopBits = StopBits.Two;
        break;
     
      case "Paire":
        serveurModbusPort.Parity = Parity.Even;
        serveurModbusPort.StopBits = StopBits.One;
        break;
     
      case "Impaire":
        serveurModbusPort.Parity = Parity.Odd;
        serveurModbusPort.StopBits = StopBits.One;
        break;
    }
     
    Mode ASCII ou RTU
    switch (comboBoxConfigurationMode.SelectedItem.ToString())
    {
      case "Modbus Série ASCII":
        serveurModbusPort.Encoding = Encoding.ASCII;
        serveurModbusPort.DataBits = 7;
        break;
     
      case "Modbus Série RTU":
        serveurModbusPort.Encoding = Encoding.BigEndianUnicode;
        serveurModbusPort.DataBits = 8;
        break;
    }
     
    //Timeout
    if (textBoxConfigurationTimeout.Text != "0")
    {
      int serveurModbusTimeout = int.Parse(textBoxConfigurationTimeout.Text);
      serveurModbusPort.ReadTimeout = serveurModbusTimeout;
      serveurModbusPort.WriteTimeout = serveurModbusTimeout;
    }
    else
    {
      serveurModbusPort.ReadTimeout = SerialPort.InfiniteTimeout;
      serveurModbusPort.WriteTimeout = SerialPort.InfiniteTimeout;
    }

  13. #13
    Membre actif
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    238
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 238
    Points : 269
    Points
    269
    Par défaut
    La configuration du Port va te permettre de communiquer avec un autre port de la même configuration. Mais il ne permet pas d'interpréter les trames qui y circulent. C'est une histoire de couche OSI :p
    L'objet SerialPort est de couche physique, le reste c'est à toi de le faire, mais franchement le protocole Modbus est pas trop complexe !
    « L’erreur est humaine, mais un vrai désastre nécessite un ordinateur »

  14. #14
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 58
    Points : 34
    Points
    34
    Par défaut
    Ca avance petit à petit, cependant j'ai une autre question. Si je fais plusieurs tableaux de byte pour représenter les différents champs d'une trame modbus
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    byte[] startField;
    byte[] addressField;
    ...
    Cela revient-il au même (au niveau envoi de données via le port série) si je les mets tous ensuite dans un même tableau de byte (byte[] myFrame) ou si je les envois tableau par tableau? (j'entends par là est ce que si par exemple j'envois tout dans un seul tableau et que donc ça n'envoie qu'une seule trame d'un coup, est ce que si j'envois les tableaux les uns après les autres dans l'ordre ça les enverra également tout d'un coup ou est ce que l'envoi se fera en "plusieurs" fois)

Discussions similaires

  1. Réponses: 2
    Dernier message: 22/02/2006, 17h41
  2. Réponses: 1
    Dernier message: 01/02/2006, 17h48
  3. Client-serveur avec VB6 inside
    Par kremvax dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 28/11/2005, 13h08
  4. Problème avec port Série sur Win XP
    Par alexorel dans le forum MFC
    Réponses: 9
    Dernier message: 27/10/2005, 15h32
  5. [SOCKET] connexion client serveur avec applet
    Par kaiser2003 dans le forum Applets
    Réponses: 2
    Dernier message: 06/10/2004, 22h32

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