Aller au contenu

Mon premier tchat, le faire focntionner hors LAN


Taurus

Messages recommandés

Bonjour à toutes et à tous !

 

Part une nuit d'insomnie je me suis lancé à programmer un tchat en langage C ... 

 

Après plusieurs échec, et méthodes essayé je suis enfin arrivé à quelque chose de potable !

 

Mon programme comporte 3 fichiers : 

- Un fichier "pour écrire", un exécutable ou l'utilisateur tape un texte

- Un fichier "pour lire", ou l'utilisateur ne peut rien faire, juste lire le texte qu'il a taper et le texte que les autres utilisateurs ont tapé

- Un fichier "serveur", fichier texte, ou est stocké la conversation

 

En gros l'utilisateur lance 2 exe, un pour lire  et un pour écrire, le fichier texte enregistre les conversations.

 

Bon pour l'instant aucun soucis, j'ai créer un groupe résidentiel, et entre 2 pc du même réseau, je parvient à communiquer.

 

Je vois maintenant les choses en grand et je voudrais le faire fonctionner entre 2 pc qui ne sont pas sur le même réseau.

 

Pour ouvrir le fichier j'utilise donc : fichier=fopen("salon","a+"); (ou r+ suivant le fichier écrire ou lire )

 

Faut il seulement mettre l'adresse ip et le chemin d'accès dans la fonction ? ou est ce plus dure ? quel serait la syntaxe ?

 

Merci d'avoir lu, bonne journée =)

 

 

Lien vers le commentaire
Partager sur d’autres sites

Salut,

 

Je ne suis pas un expert du C mais il vaudrait mieux passer par un socket pour une appli réseau que par un partage de fichier.

Sur internet c'est la jungle si tu laisses un fichier ouvert en écriture ... bha je te dis pas ce que tu vas y retrouver :D

Lien vers le commentaire
Partager sur d’autres sites

+1 Faut utiliser les sockets, les bibliothèques pour communiquer en réseau. Faudra apprendre à faire la connexion, l'envoie et la réception de données.

 

Voici un lien : http://broux.developpez.com/articles/c/sockets/

 

Pour connecter deux pc : Faudrait qu'ils connaissent leurs ip et pour ça y a un serveur d'écoute qui liste les clients qui ont lancé le programme.

Lien vers le commentaire
Partager sur d’autres sites

  • 2 semaines après...

Bonjour à toutes et à tous

 

Je réouvre le sujet puisque depuis mon dernier passage j'ai quelque peu fait évoluer mon programme.

 

J'ai réussi à créer un serveur et un client, je peux recevoir et envoyer une chaine de caractère entre deux pc distant sur internet(merci les sockets !). 

 

Il me reste à présent à créer le serveur en "multi client". 

 

Pour cela le serveur doit en permanence, détecter si un client se connecte et l'accepter. Mais aussi garder la connexion avec les client précedent et continuer a lui envoyer des informations. 

 

Sur plusieurs cour/tuto on me parle d'utiliser des "threads" pour créer un serveur multi client. 

 

Comment grâce aux threads je peux effectuer 2 taches/processsu dans une seul fenêtre DOS ?  différence entre un threads et une fonction ?

 

Merci d'avoir lu, bonne journée =)

Lien vers le commentaire
Partager sur d’autres sites

Je passe par ici et voici l'explication théorique

  • un processus == ton programme
  • Un thread (*) c'est un processus mais qui partage la mémoire avec les autres threads.

 

Donc en gros, tu vas avoir ton programme (processus) qui va tourner et à l'intérieur tu vas créer/ gérer/ ... des threads pour faire des tâches en parallèle

 

Le programmation multitâche est assez difficile  :windu:  parce que

  1. Il faut synchroniser les threads (**). Par exemple ton thread principal (<- lui existe toujours) doit attendre que le thread réseau ait reçu les informations
  2. Il y a différents problèmes avec les threads:
    • race condition: tes threads n'arrivent pas dans le bon ordre et cela représente un pourcentage très très faible des cas (dans un cas exceptionnel/ conditions bizarres/ ...)
    • deadlock: les threads s'attendent (un attend une ressource qui appartient à un autre) 

 

** -> Mutex, sémaphore, section critique, flag, monitor ... vont être tes amis :D

 

 

De plus comme tu travailles en C le choix de la bibliothèque qui propose les threads va être réduit: API native Windows ou Pthreads

 

 

Sinon le principe est assez simple :D (à moins que ce ne soit plus compliqué :dd:Côté serveur:

  • Tu vas avoir 1 thread par client (peut-être 1 thread pour X clients pour éviter d'avoir trop de threads)
  • Un thread pour gérer les messages et les autre threads (avec des tableaux)
  • En plus de ton thread principal qui lui gère l'affichage

 

 

* -> Fil d'exécution en français si je ne me trompe pas :dd:

Lien vers le commentaire
Partager sur d’autres sites

Merci de ta réponse Padawan !

 

J'ai un soucis sur mon programme, je voudrais que l'application client, envoie des messages et que l'application serveur les reçoit.

 

Si je fais un " send " et un " recv " pas de soucis, l'application serveur reçois bien le message de l'application client.

 

Cependant, dés que je boucle sur le " send " coté client, et sur le " recv " coté serveur, je ne reçois plus rien, même pas 1 msg ... :s

 

Pourtant mon application client me dit bien que le/les messages sont reçus par l'application serveur, hors je ne vois rien sur celle ci.

 

Appli Serveur

#include <time.h>#include <string.h>#include <stdlib.h>#include <stdio.h>#include <winsock2.h>typedef int socklen_t;int main(int argc , char *argv[]){   /**/        printf("\t\t Programme Serveur \n\n");    /**/    /* initialiser la bibliotheque pour utiliser les sockets *//*******************************************************************************/    printf("Initialisation de WinSock ...");printf("\n");    WSADATA wsa;    if(WSAStartup(MAKEWORD(2,2),&wsa)!=0) /*fonction qui initialise la bliblio */    {        printf("Echec, code erreur %d",WSAGetLastError());printf("\n");/* si echec, numero erreur dispo pour la focntion + tempo */        WSACleanup();/* libère les ressources alloué par la fonction WSAStartup */        exit(0); /* ferme leprog */    }    printf("Initialisation reussie !");printf("\n");/*********************************************************************************/    /**/    /* creer socket serveur */    printf("Creation du socket serveur ...\n");    SOCKET sock;    SOCKADDR_IN sin;    socklen_t recsize = sizeof(sin);    if((sock = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)    {        /* si echec, numero erreur dispo pour la focntion + tempo */        printf("Impossible de creer le sochet erreur %d\n" , WSAGetLastError());        WSACleanup();        /* ferme le socket */        closesocket(sock);        exit(0);    }    printf("Socket %d serveur creer \n", sock);/**//**/    /* creer socket client */    printf("Creation du socket client ...\n");;    SOCKET csock;    SOCKADDR_IN csin;    socklen_t crecsize = sizeof(csin);    if((csock = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)    {        /* si echec, numero erreur dispo pour la focntion + tempo */        printf("Impossible de creer le sochet erreur %d\n" , WSAGetLastError());        WSACleanup();        /* ferme le socket */        closesocket(csock);        exit(0);    }    printf("Socket %d client creer \n", csock);/**//****************************************************************************//* Configuration */            int PORT=1511;            int sock_err;            /*printf("Indiqué un port : "); scanf("%d", &PORT);*/            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);            /**********************************************************************/             /* Si la socket fonctionne */if(sock_err != SOCKET_ERROR){                /* Démarrage du listage (mode server) */        sock_err = listen(sock, 5);        printf("Listage du port %d...\n", PORT);                /* Si la socket fonctionne */        if(sock_err != SOCKET_ERROR)        {                /* Attente pendant laquelle le client se connecte */        printf("Patientez pendant que le client se connecte sur le port %d...\n", PORT);        csock = accept(sock, (SOCKADDR*)&csin, &crecsize);        printf("Un client se connecte avec la socket %d de %s:%d\n", csock, inet_ntoa(csin.sin_addr), htons(csin.sin_port));        int i=0;        char buffer[256];         char buffert[256];        /*printf("\nChaine a Envoyee : ");        fgets(buffer, sizeof buffer, stdin);        sock_err = send(csock, buffer, 32, 0);        if(sock_err != SOCKET_ERROR){printf("\nChaine envoyée : %s\n", buffer);}        else{printf("Erreur de transmission\n");}*/sock_err =recv(csock, buffer, 32, 0);        while(sock_err!= SOCKET_ERROR){        if((sock_err != SOCKET_ERROR )&& (strcmp(buffer, buffert)!=0)){printf("Chaine Recu : %s\n", buffer);for(i=0;i>=256; i++){buffert[i]=buffer[i];}i=0;}        else{printf("Erreur de reception\n");}        memset (buffer, 0, sizeof (buffer));}        /* Il ne faut pas oublier de fermer la connexion (fermée dans les deux sens) */        shutdown(csock, 2);        }else{perror("listen");}}else{perror("bind");}                /*******************************************************/    shutdown(sock, 2);    shutdown(csock, 2);    closesocket(sock);    closesocket(csock);    WSACleanup();    system("PAUSE");}
Appli Client#include <winsock2.h>#include <stdio.h>#include <stdlib.h>#define PORT 1511typedef int socklen_t;int main(void){    /**/        printf("\t\t Programme Client \n\n");    /**//**/    /* initialiser la bibliotheque pour utiliser les sockets */    printf("Initialisation de WinSock ...\n");    WSADATA wsa;    /* fonction qui initialise la bliblio */    if(WSAStartup(MAKEWORD(2,2),&wsa)!=0)    {        /* si echec, numero erreur dispo pour la focntion + tempo */        printf("Echec, code erreur %d\n",WSAGetLastError());        /* libère les ressources alloué par la fonction WSAStartup */        WSACleanup();         /* ferme leprog */        exit(0);    }    printf("Initialisation reussie ! \n");/**//**/    /* creer socket serveur */    printf("Creation du socket pour le serveur ...\n");    SOCKET sock;    SOCKADDR_IN sin;    socklen_t recsize = sizeof(sin);    if((sock = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)    {        /* si echec, numero erreur dispo pour la focntion + tempo */        printf("Impossible de creer le sochet erreur %d\n" , WSAGetLastError());        WSACleanup();        /* ferme le socket */        closesocket(sock);        exit(0);    }    printf("Socket %d serveur creer \n", sock);/**//**/    char buffer[256];/* texte */    int sock_err;    /* Configuration de la connexion */    sin.sin_addr.s_addr = inet_addr("XXX.XXX.XXX.XXX");    sin.sin_family = AF_INET;/* type */    sin.sin_port = htons(PORT);/*port */    /* Création de la socket */    sock = socket(AF_INET, SOCK_STREAM, 0);/**/    if(sock!=SOCKET_ERROR)    {        sock_err=connect(sock, (SOCKADDR*)&sin, sizeof(sin));            /* Si le client arrive à se connecter */        if( sock_err!= SOCKET_ERROR)        printf("Connexion à %s sur le port %d \n", inet_ntoa(sin.sin_addr), htons(sin.sin_port));            /*reception de donnée et affichage*/       /* if(recv(sock, buffer, 32, 0) != SOCKET_ERROR){printf("\nChaine Recu : %s\n", buffer);}*/while (sock_err=SOCKET_ERROR){            /*saisi de donnée et affichage */        printf("Chaine Envoyee a Envoyee : ");        fgets(buffer, sizeof buffer, stdin);            /*envoi de donnée */        sock_err = send(sock, buffer, 32, 0);        if(sock_err != SOCKET_ERROR){printf("\nChaine Envoyee : %s\n", buffer);}        else{printf("Impossible de se connecter\n");}}        /* On ferme la socket précédemment ouverte */        closesocket(sock);        WSACleanup();    }system("pause");}
Lien vers le commentaire
Partager sur d’autres sites

Bonjour RinDman

 

Alors je veux envoyer un message ( prog client ), et l'afficher ( prog serveur ) => en boucle.

 

Par la suite j'enregistrerais les message dans un txt, et le prog les liera. Pour l'instant j'essaye simplement d'afficher les message client sur la fenetre prog.

 

EDIT : 

 

serveur

#include <time.h>#include <string.h>#include <stdlib.h>#include <stdio.h>#include <winsock2.h>#include <unistd.h>#define TAILLE_NOM 20typedef int socklen_t; int main(int argc , char *argv[]) {  /**/        printf("\t\t Programme Serveur \n\n");    /**/  /**/    WSADATA wsa;     WSAStartup(MAKEWORD(2,2),&wsa);     SOCKET sock;    SOCKADDR_IN sin;    socklen_t recsize = sizeof(sin);    sock = socket(AF_INET , SOCK_STREAM , 0 );     SOCKET csock;    SOCKADDR_IN csin;    socklen_t crecsize = sizeof(csin);    csock = socket(AF_INET , SOCK_STREAM , 0 );      int PORT=1511;    int sock_err;    /*printf("Indiqué un port : "); scanf("%d", &PORT);*/    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);     int r;    char *name;    name = (char *) malloc(TAILLE_NOM);    r = gethostname(name,(size_t) TAILLE_NOM);     printf("Serveur sur %s initialise sur le PORT %d !\n", name, PORT);     sock_err = listen(sock, 5);       char buffer[256]; while(1){            csock = accept(sock, (SOCKADDR*)&csin, &crecsize); /* struct timeval timeout;timeout.tv_sec = 1; /* 1 s *//* timeout.tv_usec = 5 * 100 * 1000; /* 500 ms */             fd_set readfs;            int ret = 0;            FD_ZERO(&readfs);            FD_SET(csock, &readfs);    if((ret = select(csock + 1, &readfs, NULL, NULL, /*&timeout*/NULL)) < 0)   {      perror("select()");      exit(errno);   }    if(FD_ISSET(csock, &readfs))   {        recv(csock, buffer, 256, 0);        if(buffer[0]!=0){        printf("Chaine Recu : %s\n", buffer);        memset (buffer, 0, sizeof (buffer));}/* des données sont disponibles sur le socket */   }  }     shutdown(sock, 2);    shutdown(csock, 2);    closesocket(sock);    closesocket(csock);    WSACleanup();    system("PAUSE");}

Client 

#include <winsock2.h>#include <stdio.h>#include <stdlib.h>#define PORT 1511 typedef int socklen_t; int main(void){    /**/        printf("\t\t Programme Client \n\n");    /**/     WSADATA wsa;    WSAStartup(MAKEWORD(2,2),&wsa);     SOCKET sock;    SOCKADDR_IN sin;    socklen_t recsize = sizeof(sin);     char buffer[256];/* texte */    char s[]="/exit";    int sock_err;     sin.sin_addr.s_addr = inet_addr("XXX.XXX.XXX.XXX");    sin.sin_family = AF_INET;/* type */    sin.sin_port = htons(PORT);/*port */     printf("Connexion à %s sur le port %d \n", inet_ntoa(sin.sin_addr), htons(sin.sin_port)); while((sock_err!=SOCKET_ERROR)&&(strncmp(s, buffer,5)!=0)) {    sock = socket(AF_INET, SOCK_STREAM, 0);    sock_err=connect(sock, (SOCKADDR*)&sin, sizeof(sin));     memset (buffer, 0, sizeof (buffer));    printf("Chaine a Envoyee : ");    fgets(buffer, sizeof buffer, stdin);    sock_err=send(sock, buffer, 256, 0);    closesocket(sock);} WSACleanup(); system("pause"); }

J'utilise la fonction "selec()" pour rendre la fonction "recv" du serveur non bloquante ... ( petite explication ? ^^)

Cela ma permet de savoir si il y a sur les descipteurs surveillé des donnée a lire. 

Parfait, j'ai implanté le script de http://broux.developpez.com/articles/c/sockets/#L5-3-2-b

Mais je trouve quand même cela bizarre de devoir refaire 

sock = socket(AF_INET, SOCK_STREAM, 0);sock_err=connect(sock, (SOCKADDR*)&sin, sizeof(sin));

Au debut du while du programme client.

Lien vers le commentaire
Partager sur d’autres sites

Ton code me semble m*rd*que :D

 

Pour le client tu envoies toujours ton buffer (aucune incrémentation ni aucune section critique) et ton client étant en UDP tu n'as pas besoin de le connecter mais il faut utiliser la fonction sendto (si je ne dis pas de bêtises :D )

 

Voici le meilleur lien sur les sockets avec du code

 

La fonction select permet de configurer ta socket, notamment mettre un délai d'attente, mais c'est chiant parce que tu es obligé d'utiliser un fd_set et de savoir si c'est en lecture ou en écriture.

 

 

 

Édit: La programmation socket m'a toujours gonflé parce que tu as une petite 10 de fonctions, donc cela te semble simple mais tu ne peux pas faire ce que tu veux: il y a un ordre d'appels spécifiques dans chaque cas (TCP, UDP par exemple)

Lien vers le commentaire
Partager sur d’autres sites

Salut Fœtus, 

 

"ton client étant en UDP tu n'as pas besoin de le connecter mais il faut utiliser la fonction sendto (si je ne dis pas de bêtises  :D )" 

Heuuu je croyais l'avoir fait en TCP, comment vois tu qu'il est en UDP ?

Merci de ta réponse, troublante !

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...