Site icon AranaCorp

Communication entre deux programmes C via sockets

Les sockets sont un outil puissant en programmation C afin d’échanger des données entre différentes application. Les socket peuvent être utilisé avec différents langage de programmation. Dans ce tutoriel, nous allons créer deux programmes qui communique à travers d’un socket.

Principe

On utilise une socket TCP pour établir une connexion entre deux processus écrit en langage C.

Dans le progamme device.c, on simule la réception de booléen de flottant et d’entier et une fonction d’activation. Dans le programme commande, on simule la stimulation de ces entrées.

Code serveur

Nous allons mettre en place un serveur socket sur le port 12345, puis nous allons préparer la réception des commandes provenant du ou des clients.

// device.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef _WIN32
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#else
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif

// Etat du device
typedef struct {
    int discrete;     // 0=off, 1=on
    float analog;     // valeur analogique
    short num;        // entier 16 bits
    int led;          // 0=off, 1=on
} DeviceState;

void send_response(int client, const char *msg) {
    send(client, msg, strlen(msg), 0);
}

int main() {
#ifdef _WIN32
    WSADATA wsa; WSAStartup(MAKEWORD(2,2),&wsa);
#endif
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serv = {0};
    serv.sin_family = AF_INET;
    serv.sin_port = htons(12345);
    serv.sin_addr.s_addr = INADDR_ANY;

    bind(sockfd,(struct sockaddr*)&serv,sizeof(serv));
    listen(sockfd,1);
    printf("[DEVICE] En attente de connexion...\n");

    int client = accept(sockfd,NULL,NULL);
    printf("[DEVICE] Client connecte.\n");

    DeviceState state = {0,0.0,0,0};
    char buf[256];

    while(1) {
        int n = recv(client, buf, sizeof(buf)-1, 0);
        if(n<=0) break;
        buf[n]=0;
		buf[strcspn(buf,"\r\n")] = 0; // suppression retour ligne

        if(strncmp(buf,"SET_DISCRETE on",15)==0) {
            state.discrete=1;
			printf("[MCU] Discrete on\n");
            send_response(client,"OK\n");
        } else if(strncmp(buf,"SET_DISCRETE off",16)==0) {
            state.discrete=0;
			printf("[MCU] Discrete off\n");
            send_response(client,"OK\n");
        } else if(strncmp(buf,"SET_ANALOG",10)==0) {
            state.analog = atof(buf+11);
			printf("[MCU] Analog %f\n",state.analog);
            send_response(client,"OK\n");
        } else if(strncmp(buf,"SET_NUM",7)==0) {
            state.num = (short)atoi(buf+8);
			printf("[MCU] Integer %d\n",state.num);
            send_response(client,"OK\n");
        } else if(strncmp(buf,"LED on",6)==0) {
            state.led=1;
            send_response(client,"LED ON\n");
        } else if(strncmp(buf,"LED off",7)==0) {
            state.led=0;
            send_response(client,"LED OFF\n");
        }else if(strncmp(buf,"STATUS",6)==0) {
			time_t t = time(NULL);
			struct tm *tm_info = localtime(&t);
			char timestr[64];
			strftime(timestr, sizeof(timestr), "%d/%m/%Y %H:%M:%S", tm_info);

			char resp[256];
			snprintf(resp,sizeof(resp),
				"TIME=%s DISCRETE=%d ANALOG=%.2f NUM=%d LED=%d\n",
				timestr, state.discrete, state.analog, state.num, state.led);
			send_response(client,resp);

		} else if(strncmp(buf,"QUIT",4)==0) {
            send_response(client,"BYE\n");
            break;
        } else {
            send_response(client,"CMD UNKNOWN\n");
        }
    }

#ifdef _WIN32
    closesocket(client); closesocket(sockfd); WSACleanup();
#else
    close(client); close(sockfd);
#endif
    printf("[DEVICE] Arret.\n");
    return 0;
}

Code client

Dans le code client, nous allons nous connecter au serveur et définir différentes commandes afin d’interagir avec le code device. Le programme va envoyer les commandes taper dans le terminal puis va les envoyer via un flux de donnée. Il affichera dans un second temps les réponses provenant du programme device.

// commande.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#else
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif

int recv_line(int sock, char *buf, int maxlen) {
    int i=0; char c;
    while(i<maxlen-1) {
        int n=recv(sock,&c,1,0);
        if(n<=0) return n;
        buf[i++]=c;
        if(c=='\n') break;
    }
    buf[i]=0; return i;
}

int main() {
#ifdef _WIN32
    WSADATA wsa; WSAStartup(MAKEWORD(2,2),&wsa);
#endif
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serv = {0};
    serv.sin_family = AF_INET;
    serv.sin_port = htons(12345);
    serv.sin_addr.s_addr = inet_addr("127.0.0.1");

    if(connect(sockfd,(struct sockaddr*)&serv,sizeof(serv))<0) {
        perror("Connexion echouee"); return 1;
    }
    printf("[CMD] Connecte au device.\n");

    char cmd[128], buf[256];
    while(1) {
        printf("Commande (SET_DISCRETE on/off, SET_ANALOG x, SET_NUM x, LED on/off, STATUS, QUIT): ");
        if(!fgets(cmd,sizeof(cmd),stdin)) break;
        if(strncmp(cmd,"QUIT",4)==0) {
            send(sockfd,cmd,strlen(cmd),0);
            recv_line(sockfd,buf,sizeof(buf));
            printf("[CMD] Recv: %s",buf);
            break;
        }
        send(sockfd,cmd,strlen(cmd),0);
        int n=recv_line(sockfd,buf,sizeof(buf));
        if(n>0) printf("[CMD] Recv: %s",buf);
    }

#ifdef _WIN32
    closesocket(sockfd); WSACleanup();
#else
    close(sockfd);
#endif
    return 0;
}

Compilation et test

Les commandes de compilation pour les différentes machines sont sensiblement les mêmes si ce n’est que sur linux la librairie socket existe par défaut.

gcc device.c -o device
gcc commande.c -o commande

Compilation pour windows

gcc device.c -o device.exe -lws2_32
gcc commande.c -o commande.exe -lws2_32

Lancer d’abord device.exe dans un premier terminal, puis commande.exe dans un second. Vous pouvez ensuite tester les commandes définies et observer la communication via socket entre les deux programmes C.

L’outil socket permettent de communiquer entre programme de différents langage comme C et Python notamment via Wifi.

Sources

Quitter la version mobile