Windows: Socket en C "Envoyer une structure"

Fermé
poparnassus Messages postés 426 Date d'inscription vendredi 28 mars 2014 Statut Membre Dernière intervention 25 décembre 2019 - Modifié par poparnassus le 13/02/2017 à 19:42
poparnassus Messages postés 426 Date d'inscription vendredi 28 mars 2014 Statut Membre Dernière intervention 25 décembre 2019 - 24 févr. 2017 à 19:34
Bonjour,

A tenir compte qu'il a certaine chose que je pige pas ... j'apprends le C.

Depuis mon Client je souhaite envoyer une structure de type int a mon serveur, mon serveur doit boucler en permanence et m'afficher mes 7 variables de type int, sauf des qu'ils réceptionne \STOP
Mes codes sont incomplets, je patauge un peu ^^
  • EDIT: Je viens de m'apercevoir d'un probleme:

Dans ma structure les 2 variables int PRoueG et int PRoueD corresponde a deux tension moteur, du coup elle doivent utiliser le protocole UDP parceque je veux pas que mon programme bloque,
Alors que
 int BOUTTON_A; int BOUTTON_B ;int BOUTTON_Y ;  int BOUTTON_X ;
corresponde a des interrupteurs donc la elle doivent etre bloquante,
Du coup est ce que je peux coder une appli serveur qui utilise l'udp et le tcp ?
Ca a lair encore plus compliquer ...

//Prototype du client
#if defined (WIN32)
    #include <winsock2.h>
    typedef int socklen_t;
#elif defined (linux)
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #define INVALID_SOCKET -1
    #define SOCKET_ERROR -1
    #define closesocket(s) close(s)
    typedef int SOCKET;
    typedef struct sockaddr_in SOCKADDR_IN;
    typedef struct sockaddr SOCKADDR;
#endif
#include <stdio.h>
#include <stdlib.h>
#define PORT 23
#define IP
 //Structure qui gere les evenements joystick, clavier
typedef struct Input Input;
struct Input
{
    //Mode de pilotage
    int mode_pilotage;

    int PRoueG ;
    int PRoueD ;
    int BOUTTON_A; //5- 0 Pour Boutton Relacher
    int BOUTTON_B ;//6
    int BOUTTON_Y ;//7
    int BOUTTON_X ;//8
};

Client
#include "prototype.h"

int main(int argc, char** argv)
{
    #if defined (WIN32)
        WSADATA WSAData;
        int erreur = WSAStartup(MAKEWORD(2,2), &WSAData);
    #else
        int erreur = 0;
    #endif

    SOCKET sock;
    SOCKADDR_IN sin;
    char buffer[32] ;
    int nombre_de_caractere;

    //Init structure
    Input input;


    input.PRoueG = -40;
    input.PRoueD = 80;
    input.BOUTTON_Y = 1;
    input.BOUTTON_B = 0;
    input.BOUTTON_A = 1;
    input.BOUTTON_X = 1;

    if(!erreur)
    {
         /* Création de la socket */
        sock = socket(AF_INET, SOCK_STREAM, 0);

        /* Configuration de la connexion */
        sin.sin_addr.s_addr = inet_addr("127.0.0.1");
        sin.sin_family = AF_INET;
        sin.sin_port = htons(PORT);

        /* Si le client arrive à se connecter */
        if(connect(sock, (SOCKADDR*)&sin, sizeof(sin)) != SOCKET_ERROR)
        {
            printf("Connexion à %s sur le port %d\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port));

            /* Comment faut il utiliser le buffer pour transmettre les donnees suivante?
            {
            Valeur comprise entre -100 et 100
            input.PRoueG;
            input.PRoueD;}

            {
            Valeur 0 ou 1
            input.BOUTTON_Y;
            input.BOUTTON_B;
            input.BOUTTON_A;
            input.BOUTTON_X;
            }
            tab[6]={input.PRoueG,input.PRoueD,input.BOUTTON_Y,input.BOUTTON_B,input.BOUTTON_A,input.BOUTTON_X}
             Je m'embrouille un peu avec les pointeur "->" ou "."
            tab[6]={input->PRoueG,input->PRoueD,input->BOUTTON_Y,input->BOUTTON_B,input->BOUTTON_A,input->BOUTTON_X}

            Comment passer mon tab[6] dans le buffer
            */


            //ENVOI DONNEES
            strcpy(buffer,"x123xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); //copy la chaine dans buffer
            //buffer=input->PRoueG;
            nombre_de_caractere=send(sock,buffer,strlen(buffer),0);
            if(nombre_de_caractere==SOCKET_ERROR)
            {
                printf("Impossible d'envoyer les donnees \n");
            }
            else
            {
                printf("Envoyer au serveur: %s\n",buffer);
            }
        }
        else
        {
            printf("Impossible de se connecter: Serveur fermee\n");
            system("pause");
            return EXIT_FAILURE;
        }



        /* On ferme la socket précédemment ouverte */
        closesocket(sock);

        #if defined (WIN32)
            WSACleanup();
        #endif
    }
    return EXIT_SUCCESS;
}


SERVEUR
int main(void)
{
    #if defined (WIN32)
        WSADATA WSAData;
        int erreur = WSAStartup(MAKEWORD(2,2), &WSAData);
    #else
        int erreur = 0;
    #endif

    /* Socket et contexte d'adressage du serveur */
    SOCKADDR_IN sin;
    SOCKET sock;
    char buffer[32];

    socklen_t recsize = sizeof(sin);

    /* Socket et contexte d'adressage du client */
    SOCKADDR_IN csin;
    SOCKET csock;
    socklen_t crecsize = sizeof(csin);

    int sock_err;
    int nombre_de_caractere;


    /* Si les sockets Windows fonctionnent */
    if(!erreur)
    {
        /* Création d'une socket */
        sock = socket(AF_INET, SOCK_STREAM, 0);

        /* Si la socket est valide */
        if(sock != INVALID_SOCKET)
        {
            printf("La socket %d est maintenant ouverte en mode TCP/IP\n", sock);

            /* Configuration */
            sin.sin_addr.s_addr = htonl(INADDR_ANY);  /* Adresse IP automatique */
            sin.sin_family = AF_INET;                 /* Protocole familial (IP) */
            sin.sin_port = htons(PORT);               /* Listage du port */

            sock_err = bind(sock, (SOCKADDR*)&sin, recsize);
            if(sock_err!=0)
            {
                printf("Impossible d'ecouter ce port: %d \n",sock_err);
            }
            else
            {
                printf("Bind OK\n");



                sock_err = listen(sock, 5);
                printf("Listen OK PORT: %d \n", PORT);


                // Acceptation de la demande
                printf("Patientez pendant que le client se connecte sur le port %d...\n", PORT);
                csock=accept(sock, (SOCKADDR*)&csin, &crecsize);
                if(sock_err==SOCKET_ERROR)
                {
                    printf("\nDesole, je ne peux pas accepter la session TCP du a l'erreur : %d \n",WSAGetLastError());
                    return EXIT_FAILURE;
                }
                else
                {
                    printf("Un client se connecte avec la socket %d de %s:%d \n", csock, inet_ntoa(csin.sin_addr), htons(csin.sin_port));

                }

                sock_err=99;
                while(sock_err!=0)// Boucle tant qu'une demande de session (SYN) tcp n'a pas été reçu
                {
                //while(1)
                //{
                    //RECEPTION DONNEES
                    nombre_de_caractere=recv(csock,buffer,32,0);
                    if(nombre_de_caractere==SOCKET_ERROR)
                    {
                        printf("Donnes non transmise \n");
                    }
                    else
                    {
                        buffer[nombre_de_caractere]=0;
                        printf("\n Client:  %s \n\n",buffer);
                        system("cls");
                    }
                }
            }

            shutdown(csock, 2);
        }
        else
        {
            printf("erreur socket\n");
        }
             /* Fermeture de la socket client et de la socket serveur */
            printf("Fermeture de la socket client\n");
            closesocket(csock);
            printf("Fermeture de la socket serveur\n");
            closesocket(sock);
            printf("Fermeture du serveur terminee\n");
    }

    #ifdef WIN32
       WSACleanup();
    #endif
    //system("pause");
    return EXIT_SUCCESS;
}


A voir également:

1 réponse

Nessdarth Messages postés 36 Date d'inscription vendredi 16 décembre 2016 Statut Membre Dernière intervention 28 février 2017 3
14 févr. 2017 à 10:22
Bonjour,

J'ai moi même une question, qu'est ce qui te fait dire que le UDP est non bloquant ???

Ce n'est pas l'utilisation de tel ou tel protocole qui va définir la caractère bloquant ou non de ton programme, mais la gestion des sockets.

Enfin je peux me tromper.
0
poparnassus Messages postés 426 Date d'inscription vendredi 28 mars 2014 Statut Membre Dernière intervention 25 décembre 2019 30
14 févr. 2017 à 12:12
J'ai surement mal compris alors.... Mais je croyais qu'nen mode TCP la fonction receiv etait bloquante ...
0
Nessdarth Messages postés 36 Date d'inscription vendredi 16 décembre 2016 Statut Membre Dernière intervention 28 février 2017 3
14 févr. 2017 à 12:49
Pour UDP, tu utilises recvfrom qui est tout aussi bloquant.

Alors il y a toujours l'utilisation de select où tu peux préciser un temps d'attente, mais tant que tu n'as pas atteint la durée max, le programme est bloqué

L'utilisation de thread permet de rendre les choses les non-bloquantes
0
poparnassus Messages postés 426 Date d'inscription vendredi 28 mars 2014 Statut Membre Dernière intervention 25 décembre 2019 30
14 févr. 2017 à 16:48
Ya un truc qui me turlupine, si j'utilise un thread pour et que je laisse ma socket en ecoute sans interuption, sauf a la mise hors tension du matos, es que ca consome beaucoup de ressource ? de courant ?
0
Nessdarth Messages postés 36 Date d'inscription vendredi 16 décembre 2016 Statut Membre Dernière intervention 28 février 2017 3
14 févr. 2017 à 17:17
le thread devrait agir comme le bout de code qui devait attendre la réception de données.
la question est de savoir, s'il y a vraiment nécessité que la réception de données soit non bloquante, dans le cas où le programme doit gérer d'autres événements.

Si c'est oui, je ne comprend pas pourquoi l'écoute serait sans interruption.

Quand je lis, votre code (côté serveur), bon déjà je ne vois pas trop ce qu'il doit gérer en plus de la réception de données à travers la socket, mais c'est peut-être du code qui n'a pas encore été prévu pour gérer d'autres événement. Mais il y a bien un test de sortie pour la boucle.

Un thread n'a pas pour but de tourner à l'infini, il serait ici utiliser pour un fonctionnement asynchrone dans la réception des données, mais une fois son travail réalisé, on peut l'arrêter. Un thread utilise sa propre pile d'appel, mais partage la même mémoire virtuelle que le programme. Mais pour ce qui du courant, je n'en ai aucune idée, je réfléchis en terme de programmation et non en terme matériel, mais on peut se dire sans se tromper, que 2 threads(oui car tout programme a au moins un thread, même si on ne fait pas du multithreading), c'est toujours plus gourmand qu'un seul.
0
poparnassus Messages postés 426 Date d'inscription vendredi 28 mars 2014 Statut Membre Dernière intervention 25 décembre 2019 30
15 févr. 2017 à 09:30
RE,

Bon déjà, j'ai repris le code du serveur car il doit être coder en python, je viens de faire 1000 pas en arriere lol C'est mon premier script python...

Le scrypt serveur est pas du tout développer, donc je vais vous expliquez ce que ce script doit faire, comme ca vous pourrez bien me conseiller:
- 1) il s'initialise des le démarrage du raspberry et tourne jusqu’à arrêt de la machine.
- 2) recuperer la structure du client si dessous et stocker les valeur dans une nouvelle structure cote serveur.
- 3) recuperer les images capturer par le raspberry et les transmettres au clients (je n'ai pas coder la fonction coté client qui traitera l'imùage mais je veux preparer l'envoi/reception de données, je ne sais pas si je transfert image par image au format jpg ou en texte brut mais je pense que pour linstant c'est pas important)
- 4) La carte arduino va me renvoyer certaine valeur, tel que le niveau des bateries, état des capteurs, qui seront stocker dans une structure et envoyé au client.

//Structure Client

typedef struct Input Input;
struct Input
{   
    //Les 2 variables si dessous corresponde a la tension moteur du vehicule. Elle seront transmise à la carte arduino. Elle doivent arriver en temp reel au moteur, la derniere données doit ecraser la precedente en quelque sorte.
    int PRoueG ; //valeur: -100 à 100 %,, la convertion % à tension se fait dans le code de la carte aduino
    int PRoueD ;//valeur: -100 à 100 %
    
    //Les 4 variables si dessous vont commander des contacteurs electriques sur le raspberry 
    int BOUTTON_A; //valeur : 1 ou 0
    int BOUTTON_B ;//valeur: 1 ou 0
    int BOUTTON_Y ;//valeur : 1 ou 0
    int BOUTTON_X ;//valeur : 1 ou 0
};


Es que j'utilise une ou plusieurs socket .?
je pense que je vais devoir utiliser plusieur thread, un pour le 2) et le 3) et le 4)
Si j'ai bien compris le thread, il s'appliqe a une fonction. j'applique un thread ic
fonction_data_pilotage()
et un la
fonction_data_video()


je vias poster un code serveur grossier histoire de voir a quoi ca ressemble
0