Bien programmer en langage C
Vous souhaitez réagir à ce message ? Créez un compte en quelques clics ou connectez-vous pour continuer.
Le Deal du moment : -23%
EVGA SuperNOVA 650 G6 – Alimentation PC 100% ...
Voir le deal
77.91 €

problèmes généraux avec les sockets et les threads

2 participants

Page 1 sur 2 1, 2  Suivant

Aller en bas

problèmes généraux avec les sockets et les threads Empty problèmes généraux avec les sockets et les threads

Message  trunks Ven 7 Nov 2008 - 19:46

Salut à tous,
Merci à Emdel pour avoir offert ce forum,
J'ai pas mal de questions à poser mais elles viendront au fur et à mesure que d'autres réponses viennent. Je précise que je n'avais pas encore utilisé les sockets et les threads avant l'écriture de cette application .

J'écris une application de vente(et de gestion) de crédit pour cybercafé (client/serveur) et j'ai une mauvaise maitrise de l'utilisation des sockets dans mon application . Mon code est bien sûr basé sur celui donné par -ed- dans son tutoriel.
(code plus bas)


Ce que je veux obtenir est ceci:

COTE SERVEUR:

le serveur est là et écoute:
-un client doit se connecter et lui envoyer le login (de l'internaute)
-il reçoit le login, lance une requête sur la base pour sélectionner le temps restant correspondant à ce login. Après certaines vérifications, si tout est OK, il fait une décompte de l'heure, fait un UPDATE du champ temps de la base(correspondant au login) et envoie au client le temps restant qui doit être toujours affiché en temps réel chez ce dernier.

COTE CLIENT:
-Dans une boucle, le client reçoit,le temps qui lui est envoyé et l'affiche sur un label sur l'interface.

Mes inquiétudes sont les suivantes:

-Il arrive que pendant un moment, la décompte s'arrête (problème de boucle?? le code est en bas) Qu'est ce qui arrête cela je ne sais pas.

-Quand bien que le client est fermé la décompte au niveau du serveur continue (comment l'arrêter?).




Je préfère commencer par ces deux questions. Et puis veuillez critiquer au maximum et corriger moi SVP le code que je mettrai ci-dessous:

Quelques précisions:

-Dans la partie serveur, la boucle d'attente de connection d'un client est lancé dès l'affichage de l'IHM
-Dans la prtie cliente, tout commence après un clic sur un bouton:



/*-----------------------------*/
Dans la partie SERVEUR:

- La fonction clients ne change pas et est équivaut à celle du tutoriel d'Emdel

//Fonction client du tutoriel d'Emdel avec d'autres ajouts

Code:
static void *client(void *data){
    struct cli *p=(struct cli*)data;
    MYSQL *mysql;
   
  do{
        char message[31]={0};
        char login[36]={0};
        char reponse[21]={0};
        //MYSQL *mysql;
        MYSQL_RES *result;
        MYSQL_ROW row;
        MYSQL_ROW row2;
        int rep=0;
        char copie_reponse[21]={0};
        rep=recv(p->sock,message,sizeof(message),0);
        if(rep!=SOCKET_ERROR){
            if(strcmp(message,"CONNECTED")==0){
                send(p->sock,"CONNECTED_OK",(int)strlen("CONNECTED_OK"),0);
                rep=recv(p->sock,login,sizeof(login),0);
                if(rep!=SOCKET_ERROR){
                    char copie_result[121]={0};

                    mysql=mysql_init(NULL);
                    mysql_real_connect(mysql,"localhost","root",NULL,"skull",3306,NULL,0);
                    gchar *requete=g_strdup_printf("select login from clients where login='%s'",login);
                    mysql_query(mysql,requete);
                    g_free(requete);
                    result=mysql_use_result(mysql);
                    while(row=mysql_fetch_row(result)){
                      strcpy(copie_result,row[0]);
                    }

                    mysql_free_result(result);
                    if(copie_result!=NULL){//Revoir ce controle ça ne doit pas être NULL ici
                        int temps=0;
                        gchar *requete=g_strdup_printf("select temps from clients where login='%s'",login);
                        mysql_query(mysql,requete);
                        g_free(requete);
                        result=mysql_use_result(mysql);
                        while(row2=mysql_fetch_row(result)){
                        temps=atoi(row2[0]);
                        }
                        mysql_free_result(result);
                        //Mettre le temps dans un fichier
                        FILE *fic_tmps=fopen("temps.txt","w");
                        fprintf(fic_tmps,"%d",temps);
                        fclose(fic_tmps);
                       
                        if(temps==0){
                        gchar *msg=g_strdup("Vous n'avez plus de minutes restantes");
                        send(p->sock,msg,(int)strlen(msg),0);
                        return;
                        } else{
                            send(p->sock,"ALL_OK",(int)strlen("ALL_OK"),0);
                           
                            recv(p->sock,reponse,(int)sizeof(reponse),0);
                            if(strcmp(reponse,"TIME")==0){
                                time_t heure_depart;
                                time_t heure_actuel;
                               
                                heure_depart=time(NULL);
                                heure_actuel=time(NULL);
                                while(difftime(heure_actuel,heure_depart)<temps){
                               
                                    div_t t;
                                    int h=0,m=0; char hm[11]={0};
                                   
                                    Sleep(1000);
                                    temps=temps-1;
                                    gchar *requete=g_strdup_printf("UPDATE clients SET temps=%d WHERE login='%s'",temps,login);
                                    mysql_query(mysql,requete);
                                    g_free(requete);
                                    t=div(temps,60);
                                    h=t.quot;
                                    m=t.rem;
                                   
                                    if(h==0 && m==0){
                                        strcpy(hm,"FIN");
                                        send(p->sock,hm,(int)sizeof(hm),0);
                                        break;
                                    } else {
                                        sprintf(hm,"%d:%d",h,m);
                                        send(p->sock,hm,(int)sizeof(hm),0);
                                    }
                                    heure_actuel=time(NULL);
                                }
                           
                            }
                           
                            return;

                        }

                  } else {
       
                        send(p->sock,"Ce compte et/ou ce mot de passe n'existe pas",(int)strlen("Ce compte et/ou ce mot de passe n'existe pas"),0);
                        return;
                    }
                } else {
                        gchar *msg=g_strdup("Erreur de reception du serveur!");
                        send(p->sock,msg,(int)strlen(msg),0);
                        return;
                    }
        }

        }


    }while(1);
    mysql_close(mysql);
   
    free(p);
}

//Fonction App appelé par un thread après affichage de l'IHM

Code:
void *App(void *data)
{
    SOCKET sock;
    SOCKADDR_IN sin;
    //pthread_t thr;

    sock=socket(AF_INET,SOCK_STREAM,0);
    sin.sin_addr.s_addr=htonl(INADDR_ANY);
    sin.sin_family=AF_INET;
    sin.sin_port=htons(SERVER_PORT_LISTENING);

    bind(sock,(SOCKADDR*)&sin,sizeof(sin));
    listen(sock,5);

    clients((void*)sock);
}
/*----------------------------------------------*/

Dans la partie cliente:

Code:
void connect_to_serveur(GtkWidget *widget, gpointer data)
{
    pthread_t thread;
    pthread_create(&thread,NULL,App,data);
}

Code:
void *App(void *data)
{
  SOCKET sock;
  SOCKADDR_IN sin;
  FILE *fp=NULL;
  char reponse[31]={0};
  char reponse2[131]={0};
  char temps[10]={0};

  char ip_serveur[16]={0};

  fp=fopen("ip.txt","r");
  fgets(ip_serveur,sizeof(ip_serveur),fp);
  fclose(fp);

  sock=socket(AF_INET,SOCK_STREAM,0);
  sin.sin_addr.s_addr=inet_addr(ip_serveur);
  sin.sin_family=AF_INET;
  sin.sin_port=htons(SERVER_PORT_CONNEXION);

  if(connect(sock,(SOCKADDR*)&sin,sizeof(sin))!=SOCKET_ERROR){
       
        send(sock,"CONNECTED",(int)strlen("CONNECTED"),0);
        recv(sock,reponse,sizeof(reponse),0);
        if(strcmp(reponse,"CONNECTED_OK")==0){

          //Récupération du LOGIN saisi par l'utilisateur
            const gchar *login=gtk_entry_get_text(GTK_ENTRY(data));

            char login_s[36]={0};
            strcpy(login_s,login);
            send(sock,login_s,(int)sizeof(login_s),0);

            recv(sock,reponse2,sizeof(reponse2),0);
            if(strcmp(reponse2,"ALL_OK")!=0){
                gchar *message=g_strdup_printf("%s",reponse2);
                informations(message);
                g_free(message);
                return;
            } else {
                send(sock,"TIME",(int)strlen("TIME"),0);
    //Boucle qui reçoit le temps envoyé et l'affiche dans un label
                for(;;){
                recv(sock,temps,(int)sizeof(temps),0);
                if(strcmp(temps,"FIN")!=0){
                    while(gtk_events_pending()){
                        gtk_main_iteration();
                    }
                    gtk_label_set_text(GTK_LABEL(hm_restantes),temps);

                } else {
                    break;
                }

                }

            }
        } else {
            erreur("Pas de reponse du serveur");
            return;
        }

    } else {
    erreur("Impossible de se connecter au serveur");
    return;
    }
shutdown(sock, 2);
closesocket(sock);
}
/*----------------*
C'est un peu long mon post mais j'espère avoir assez explicite sinon merci de le dire. NB: Critiquez ce code.

trunks
Bavard
Bavard

Messages : 18
Date d'inscription : 06/11/2008

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  -ed- Sam 8 Nov 2008 - 1:26

OK, je vais passer un bon week-end ! Laughing

Je précise que je ne répondrais que sur les aspects 'réseau', étant ignorant de l'aspect SQL.

Déjà, je te demande de poster du code compilable réduit, parce là, je en vois pas du tout comment tout ça s'enchaine... Le principe est de tester l'application d'abord en mode console pour valider les aspects réseau qui sont déjà assez complexes... Pour le moment, on a besoin ni du GUI ni du SQL.
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  trunks Sam 8 Nov 2008 - 11:23

-ed- a écrit:OK, je vais passer un bon week-end ! Laughing.

Laughing

-ed- a écrit:Je précise que je ne répondrais que sur les aspects 'réseau', étant ignorant de l'aspect SQL.

D'accord, il n'y pas de problème.

-ed- a écrit:Déjà, je te demande de poster du code compilable réduit, parce là, je en vois pas du tout comment tout ça s'enchaine... Le principe est de tester l'application d'abord en mode console pour valider les aspects réseau qui sont déjà assez complexes... Pour le moment, on a besoin ni du GUI ni du SQL.


Je ne sais pas trop quel partie de poster mais je vais essayer et tu verras si ç'est suffisant:
Coté serveur: dans le fichier connection.c
Code:
#include "connection.h"
#include "mysql.h"
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

void *clients(void *data){
    SOCKET sock=(SOCKET)data;
    struct cli *p=malloc(sizeof(struct cli));
    do{

        if(p!=NULL){
            p->recsize=(int)sizeof(p->sin);
            p->sock=accept(sock,(SOCKADDR*)&p->sin,&p->recsize);
            pthread_create(&p->thread,NULL,client,p);
    } else {
        erreur("Erreur d'allocation memoire");
        return;
    }
}while(1);
shutdown(p->sock,2);
closesocket(p->sock);
}
/*----------------------------------------------*/
/*
static void verif_connection(char *message, struct cli *p)
{
       
       
}
*/
/*----------------------------------------------*/
static void *client(void *data){
    struct cli *p=(struct cli*)data;
    MYSQL *mysql;
    //gchar *info=NULL;
  do{
        char message[31]={0};
        char login[36]={0};
        char reponse[21]={0};
        //MYSQL *mysql;
        MYSQL_RES *result;
        MYSQL_ROW row;
        MYSQL_ROW row2;
        int rep=0;
        char copie_reponse[21]={0};
        rep=recv(p->sock,message,sizeof(message),0);
        if(rep!=SOCKET_ERROR){
            if(strcmp(message,"CONNECTED")==0){
                send(p->sock,"CONNECTED_OK",(int)strlen("CONNECTED_OK"),0);
                rep=recv(p->sock,login,sizeof(login),0);
                if(rep!=SOCKET_ERROR){
                    char copie_result[121]={0};

                    mysql=mysql_init(NULL);
                    mysql_real_connect(mysql,"localhost","root",NULL,"skull",3306,NULL,0);
                    gchar *requete=g_strdup_printf("select login from clients where login='%s'",login);
                    mysql_query(mysql,requete);
                    g_free(requete);
                    result=mysql_use_result(mysql);
                    while(row=mysql_fetch_row(result)){
                      strcpy(copie_result,row[0]);
                    }

                    mysql_free_result(result);
                    if(copie_result!=NULL){//Revoir ce controle ça ne doit pas être NULL ici
                        int temps=0;
                        gchar *requete=g_strdup_printf("select temps from clients where login='%s'",login);
                        mysql_query(mysql,requete);
                        g_free(requete);
                        result=mysql_use_result(mysql);
                        while(row2=mysql_fetch_row(result)){
                        temps=atoi(row2[0]);
                        }
                        mysql_free_result(result);
                        //Mettre le temps dans un fichier
                        FILE *fic_tmps=fopen("temps.txt","w");
                        fprintf(fic_tmps,"%d",temps);
                        fclose(fic_tmps);
                       
                        if(temps==0){
                        gchar *msg=g_strdup("Vous n'avez plus de minutes restantes");
                        send(p->sock,msg,(int)strlen(msg),0);
                        return;
                        } else{
                            send(p->sock,"ALL_OK",(int)strlen("ALL_OK"),0);
                           
                            recv(p->sock,reponse,(int)sizeof(reponse),0);
                            if(strcmp(reponse,"TIME")==0){
                                time_t heure_depart;
                                time_t heure_actuel;
                               
                                heure_depart=time(NULL);
                                heure_actuel=time(NULL);
                                while(difftime(heure_actuel,heure_depart)<temps){
                                //while(1){ 
                                    div_t t;
                                    int h=0,m=0; char hm[11]={0};
                                   
                                    Sleep(1000);
                                    temps=temps-1;
                                    gchar *requete=g_strdup_printf("UPDATE clients SET temps=%d WHERE login='%s'",temps,login);
                                    mysql_query(mysql,requete);
                                    g_free(requete);
                                    t=div(temps,60);
                                    h=t.quot;
                                    m=t.rem;
                                   
                                    if(h==0 && m==0){
                                        strcpy(hm,"FIN");
                                        send(p->sock,hm,(int)sizeof(hm),0);
                                        break;
                                    } else {
                                        sprintf(hm,"%d:%d",h,m);
                                        send(p->sock,hm,(int)sizeof(hm),0);
                                    }
                                    heure_actuel=time(NULL);
                                }
                           
                            }
                           
                            return;//HMM!! faut-il le laisser ici?

                        }

                  } else {
        //Cette partie ne marche pas à cause du controle mal fait au niveau de copie_result
                        send(p->sock,"Ce compte et/ou ce mot de passe n'existe pas",(int)strlen("Ce compte et/ou ce mot de passe n'existe pas"),0);
                        return;
                    }
                } else {
                        gchar *msg=g_strdup("Erreur de reception du serveur!");
                        send(p->sock,msg,(int)strlen(msg),0);
                        return;
                    }
        }

        }


    }while(1);
    mysql_close(mysql);
    //A ramerner dans clients
    //shutdown(p->sock,2);
    //closesocket(p->sock);
    free(p);
}
/*-------------------------------------------*/
void *App(void *data)
{
    SOCKET sock;
    SOCKADDR_IN sin;
    //pthread_t thr;

    sock=socket(AF_INET,SOCK_STREAM,0);
    sin.sin_addr.s_addr=htonl(INADDR_ANY);
    sin.sin_family=AF_INET;
    sin.sin_port=htons(SERVER_PORT_LISTENING);

    bind(sock,(SOCKADDR*)&sin,sizeof(sin));
    listen(sock,5);

    clients((void*)sock);


    //pthread_create(&thr,NULL,clients,(void*)sock);
}


Dans connection.h de la partie serveur

Code:
#ifndef _CONNECTION_
#define _CONNECTION_

#include <gtk/gtk.h>
#include <pthread.h>
#include <winsock2.h>

#define SERVER_PORT_LISTENING 3113
/*----------------------------------------------------------*/
struct cli{
    pthread_t thread;
    SOCKADDR_IN sin;
    int recsize;
    SOCKET sock;
};
/*---------------------------------------------------------*/
void *clients(void *data);
//static void verif_connection(char *message, struct cli *p);
static void *client(void *data);
void *App(void *data);
//void lancer_splashscreen(void);
#endif


Dans main.c du serveur
Code:
int main(int argc, char *argv[])
{
    WSADATA wsa_data;
    pthread_t thread;
  //.... des choses
WSAStartup(MAKEWORD(2, 2),&wsa_data);
//des choses
        pthread_create(&thread,NULL,App,NULL);
//....des choses 

    gtk_main();
    WSACleanup();
        return 0;
}

/****************************************************/
Code partie cliente:

NB: la fonction connect_to_serveur est déclenché après un clic sur un bouton juste après l'identification

Code:
void connect_to_serveur(GtkWidget *widget, gpointer data)
{
    pthread_t thread;
    pthread_create(&thread,NULL,App,data);
}
/*-----------------------------------------------------------*/
void *App(void *data)
{
  SOCKET sock;
  SOCKADDR_IN sin;
  FILE *fp=NULL;
  char reponse[31]={0};
  char reponse2[131]={0};
  char temps[10]={0};

  char ip_serveur[16]={0};

  fp=fopen("ip.txt","r");
  fgets(ip_serveur,sizeof(ip_serveur),fp);
  fclose(fp);

  sock=socket(AF_INET,SOCK_STREAM,0);
  sin.sin_addr.s_addr=inet_addr(ip_serveur);
  sin.sin_family=AF_INET;
  sin.sin_port=htons(SERVER_PORT_CONNEXION);

  if(connect(sock,(SOCKADDR*)&sin,sizeof(sin))!=SOCKET_ERROR){
        gtk_widget_set_sensitive(fermer,FALSE);
        gtk_widget_set_sensitive(valider,FALSE);
        gtk_widget_set_sensitive(action_but[0],TRUE);
        gtk_widget_set_sensitive(action_but[1],TRUE);
        send(sock,"CONNECTED",(int)strlen("CONNECTED"),0);
        recv(sock,reponse,sizeof(reponse),0);
        if(strcmp(reponse,"CONNECTED_OK")==0){
            const gchar *login=gtk_entry_get_text(GTK_ENTRY(data));

            char login_s[36]={0};//A enlever après
            strcpy(login_s,login);////A enlever après
            send(sock,login_s,(int)sizeof(login_s),0);

            recv(sock,reponse2,sizeof(reponse2),0);
            if(strcmp(reponse2,"ALL_OK")!=0){
                gchar *message=g_strdup_printf("%s",reponse2);
                informations(message);
                g_free(message);
                return;
            } else {
                send(sock,"TIME",(int)strlen("TIME"),0);

                for(;;){
                recv(sock,temps,(int)sizeof(temps),0);
                if(strcmp(temps,"FIN")!=0){
                    while(gtk_events_pending()){
                        gtk_main_iteration();
                    }
                    gtk_label_set_text(GTK_LABEL(hm_restantes),temps);

                } else {
                    break;
                }

                }

            }
        } else {
            erreur("Pas de reponse du serveur");
            return;
        }

    } else {
    erreur("Impossible de se connecter au serveur");
    return;
    }
shutdown(sock, 2);
closesocket(sock);
}

Voilà Emdel, j'espère avoir posté les parties essentielles concernant le réseau. c'est tout de toutes les façons. S'il ya encore une autre information à donner, merci de me le dire. Bonne suite et à bientôt. Bon début de week end;-)

trunks
Bavard
Bavard

Messages : 18
Date d'inscription : 06/11/2008

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  -ed- Sam 8 Nov 2008 - 17:28

trunks a écrit:
Je ne sais pas trop quel partie de poster mais je vais essayer et tu verras si ç'est suffisant:
Ca devrait aller. Je mets mes remarques au fur et à mesure...

Code du serveur

Code:
  clients ((void *) sock);
Pratique douteuse que je déconseille (non portable). Si il n'y a qu'une valeur, je recommande
Code:
  clients (&sock);
et le pendant dans la tâche :
Code:

static void *clients (void *data)
{
  SOCKET *psock = data;
  if (psock != NULL)
  {
      SOCKET sock = *psock;

Code:

static void *clients (void *data)
{
    <...>
        else
        {
            erreur ("Erreur d'allocation memoire");
            return;
        }
La fonction retourne une adresse (ou NULL). On a pas le droit de ne rien retourner.
De plus, un fin brutale de la tâche entraine une non libération des ressources... Je déconseille l'usage de return ailleurs qu'en dernière ligne d'une fonction.

L'algo de 'clients' est faux. Il faut allouer un client à chaque tour et non une seule fois. Si c'est comme ça sur mon site, ça mérite une correction...

Dans client(), le traitement des réceptions n'est pas conforme aux exemples que j'ai donné sur le site. Il faut absolument réserver une place pour le 0 et de préférence, placer le 0 'à la main'. De plus, il faut traiter les cas d'erreur (<0) et de déconnexion (0).

http://mapage.noos.fr/emdel/reseaux.htm#texte

Ce soir, je sors. Voici l'état de mes travaux :

http://delahaye.emmanuel.free.fr/forums/trunks/
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  trunks Dim 9 Nov 2008 - 21:27

Code:
  clients ((void *) sock);
Pratique douteuse que je déconseille (non portable). Si il n'y a qu'une valeur, je recommande
Code:
  clients (&sock);

ok! bien pigé ;-)

La fonction retourne une adresse (ou NULL). On a pas le droit de ne rien retourner.

d'accord! je vais consulter tes travaux et je reviens demain te dire la suite dès que j'aurai mis ces quelques trucs en pratique. si tout est bon je vais l'adapter à mon code. Pour la suite de mes questions en voilà deux autres:

- Supposons que je veuille envoyer le login et le mot de passe au serveur avant que tout ne commence. Cela veut-il tout simplement dire que je fais 2 send() au niveau du client et 2 recv() au niveau du serveur? (logiquement oui!)

- Cette méthode de thread créée pour chaque client suffit-elle au serveur pour gérer plusieurs clients dans le réseau en même temps ou bien faut-il gérer un tableau de clients fait à la main?


Merci! je vais essayer tout ça et je te tiendrai au courant de la suite. Bonne soirée.

trunks
Bavard
Bavard

Messages : 18
Date d'inscription : 06/11/2008

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  -ed- Dim 9 Nov 2008 - 22:05

trunks a écrit:- Supposons que je veuille envoyer le login et le mot de passe au serveur avant que tout ne commence. Cela veut-il tout simplement dire que je fais 2 send() au niveau du client et 2 recv() au niveau du serveur? (logiquement oui!)
Oui, selon un protocole bien établi. Par exemple :


Client Serveur
send() ----login-------> recv()
recv() <----OK---------- send()
send() ----pass--------> recv()
recv() <----OK---------- send()


- Cette méthode de thread créée pour chaque client suffit-elle au serveur pour gérer plusieurs clients dans le réseau en même temps ou bien faut-il gérer un tableau de clients fait à la main?
Si on a besoin de faire des connexions entre clients, il faut que chaque client sache à quel autre client il doit s'adresser (le socket suffit). Il peut être nécessaire de garder en mémoire une liste des clients connectés et de la communiquer aux threads... Tout dépend de l'application et du protocole mis en œuvre. Il y a un gros travail d'étude à faire préalablement au codage.

Penser aussi à gérer la liste des clients en cas de déconnexion et aux conséquences sur une connexion client/client en cours...
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  trunks Lun 10 Nov 2008 - 19:50

pale
Hi emdel, eh oui je suis triste! il va falloir que je te demande de l'aide sur autre chose que les sockets et les threads. J'ai essayer (avec quelques difficultés) quand même d'adapter ton code au mien en y intégrant les trucs dont j'ai besoin. jusque là c'est bon!Je voudrais bien s'il te plait avant de continuer avec les questions relatives aux sockets que tu me réponds à ceci:

- Comment ferais-tu (si on te le demande) un timer de décompte de temps basé sur un temps initial donné en minutes?

j'ai l'impression que le mien a des ennuis. En tenant un peu compte de tout mon code même en ignorant la partie GUI et MYSQL tu pourras m'aider sur sur ce point. En continuant mes tests avec la nouvelle implémentation que tu m'as donné, il arrive un moment où le client me dit me dit "SERVEUR DECONNECTE". C'est le message que le client m'envoie s'il ne réceptionne plus rien (le temps décompté et envoyé par le serveur). Je pense que le blème provient peut-être de mon système de décompte de temps, je ne sais pas trop. Voudrais bien me voir ce qui se passe ou ce que tu ferais si tu étais à ma place?

Autre chose:
regarde ce code STP (mon adaptation du client que tu m'as donné):
Partie cliente:

Code:
void *client(void *data)
{
  SOCKET sock = socket (AF_INET, SOCK_STREAM, 0);
  if (sock != INVALID_SOCKET)
  {
      {
        char ip_serveur[16] = { "127.0.0.1" };

        SOCKADDR_IN sin;
        sin.sin_addr.s_addr = inet_addr (ip_serveur);
        sin.sin_family = AF_INET;
        sin.sin_port = htons (SERVER_PORT_CONNEXION);

        if (connect (sock, (SOCKADDR *) & sin, sizeof (sin)) != SOCKET_ERROR)
        {
            [b]int err = sock_send_text (sock, "CONNECTED");
            if (!err)
            {
              char *reponse = sock_recv_text_dyn (sock);

              if (reponse != NULL)
              {
                  if (strcmp (reponse, "CONNECTED_OK") == 0)
                  {
                        char login_s[36]={0};
                        const gchar *login=gtk_entry_get_text(GTK_ENTRY(data));

                        strcpy(login_s,login);
                        err=sock_send_text(sock,login_s);

                        if (!err){
                        for(;;){
                        char *reponse=sock_recv_text_dyn(sock);
                        if (reponse!=NULL)
                        {
                            while(gtk_events_pending())
                            {
                                gtk_main_iteration ();
                            }

                        gtk_label_set_text(GTK_LABEL(hm_restantes),reponse);
                        free(reponse),reponse=NULL;
                        } else if(strcmp(reponse,"FIN")==0){
                            informations("TERMINE");
                            break;
                            return;
                        }
                        //free(reponse),reponse=NULL;
                    }

                  assert(reponse==NULL);
                }//Fin comparaison avec CONNECTED_OK

            } else {
                    erreur("Erreur de réception");
            }
            free (reponse), reponse = NULL;[/b]
            }
            else
            {
                  //printf ("CLI erreur serveur\n");
            }
            assert (reponse == NULL);
            }

            }
      }
      closesocket (sock), sock = INVALID_SOCKET;
  }
  assert(sock==INVALID_SOCKET);
  return NULL;

}

Ne penses-tu pas que la partie que j'ai mis en gras(réception et affichage du temps décompté envoyé par le serveur) doit normalement être mis dans une autre fonction et appelée par un thread dans la fonction client? dans ce cas closesocket sera dans la fonction de la partie mise en gras.

JE pense que toute la partie de configuration des paramètres du socket doivent être dans une fonction qui doit être appelée dès l'affichage de l'interface client genre:

Code:
void *client(void *data)
{
  SOCKET sock = socket (AF_INET, SOCK_STREAM, 0);
  if (sock != INVALID_SOCKET)
  {
      {
        char ip_serveur[16] = { "127.0.0.1" };

        SOCKADDR_IN sin;
        sin.sin_addr.s_addr = inet_addr (ip_serveur);
        sin.sin_family = AF_INET;
        sin.sin_port = htons (SERVER_PORT_CONNEXION);

        if (connect (sock, (SOCKADDR *) & sin, sizeof (sin)) != SOCKET_ERROR)
        {
            printf("Connexion établie sur le serveuré);
}

}
}
}
cette fonction sera alors appelée dès que l'IHM s'affiche

et la partie mis en gras dans le code le plus long doit être appelé par un thread (donc mis dans une fonction) dès qu'on clique sur le bouton valider après identification.

Alors penses-tu que ce que je dis là peut faire l'affaire??

Maintenant revenons à nos anciens moutons ;-)
- Cette méthode de thread créée pour chaque client suffit-elle au serveur pour gérer plusieurs clients dans le réseau en même temps ou bien faut-il gérer un tableau de clients fait à la main?[/b]

Si on a besoin de faire des connexions entre clients, il faut que chaque client sache à quel autre client il doit s'adresser (le socket suffit). Il peut être nécessaire de garder en mémoire une liste des clients connectés et de la communiquer aux threads... Tout dépend de l'application et du protocole mis en œuvre. Il y a un gros travail d'étude à faire préalablement au codage.

Penser aussi à gérer la liste des clients en cas de déconnexion et aux conséquences sur une connexion client/client en cours...[/quote]

Eh bien non , les clients n'auront pas à communiquer entre eux. c'est pas prévu. seul les clients échangeront avec le serveur (dans le cas de mon appli).Sur cette réponse, je repose la question le seul thread côté client permettre t-il de gérer +sieurs clients à la fois (par le serveur bien sur):

Désolé de te déranger autant, mais si je ne fournis pas cette application à temps , je suis un homme mort ( No ). Merci d'avance et à bientôt.

trunks
Bavard
Bavard

Messages : 18
Date d'inscription : 06/11/2008

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  trunks Lun 10 Nov 2008 - 19:53

la partie mise en gras dont je parlais n'est pas affiché comme tel alors la voici:
...
int err = sock_send_text (sock, "CONNECTED");
if (!err)
{
char *reponse = sock_recv_text_dyn (sock);

if (reponse != NULL)
{
if (strcmp (reponse, "CONNECTED_OK") == 0)
{
char login_s[36]={0};
const gchar *login=gtk_entry_get_text(GTK_ENTRY(data));

strcpy(login_s,login);
err=sock_send_text(sock,login_s);

if (!err){
for(;;){
char *reponse=sock_recv_text_dyn(sock);
if (reponse!=NULL)
{
while(gtk_events_pending())
{
gtk_main_iteration ();
}

gtk_label_set_text(GTK_LABEL(hm_restantes),reponse);
free(reponse),reponse=NULL;
} else if(strcmp(reponse,"FIN")==0){
informations("TERMINE");
break;
return;
}
//free(reponse),reponse=NULL;
}

assert(reponse==NULL);
}//Fin comparaison avec CONNECTED_OK

} else {
erreur("Erreur de réception");
}
free (reponse), reponse = NULL;

...

trunks
Bavard
Bavard

Messages : 18
Date d'inscription : 06/11/2008

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  -ed- Lun 10 Nov 2008 - 20:15

trunks a écrit:- Comment ferais-tu (si on te le demande) un timer de décompte de temps basé sur un temps initial donné en minutes?
C'est un problème classique que l'on résout de la manière suivante :
Code:

echeance := heure_courante() + delai
DO
 suspendre (T)
WHILE heure_courante() < echeance
OUTPUT "delai echu" EOL

suspendre est sleep() ou usleep() sous unixoïde ou Sleep() sous Windows. T est 10 a 100 x < delai selon la précision demandée Ceci peut aider :

http://delahaye.emmanuel.free.fr/clib/psleep/

Dans une application 'online', on peut ensuite discuter pour savoir si le timer doit être géré chez le client, ou sur le serveur... (la dernière solution consomme de la bande passante pour pas grand chose et nuit au 'parallélisme').

Autre chose:
regarde ce code STP (mon adaptation du client que tu m'as donné):
Partie cliente:
Je trouve qu'il y a trop de boucles imbriquées... En principe, c'est un thread par boucle (avec au moins une fonction bloquante).

JE pense que toute la partie de configuration des paramètres du socket doivent être dans une fonction qui doit être appelée dès l'affichage de l'interface client genre:

<...>cette fonction sera alors appelée dès que l'IHM s'affiche

et la partie mis en gras dans le code le plus long doit être appelé par un thread (donc mis dans une fonction) dès qu'on clique sur le bouton valider après identification.

Alors penses-tu que ce que je dis là peut faire l'affaire??
Oui.

Eh bien non , les clients n'auront pas à communiquer entre eux. c'est pas prévu. seul les clients échangeront avec le serveur (dans le cas de mon appli).Sur cette réponse, je repose la question le seul thread côté client permettre t-il de gérer +sieurs clients à la fois (par le serveur bien sur):
Oui. Un seul thread est codé, mais il en est créé un par client.
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  trunks Mar 11 Nov 2008 - 19:40

Slt!
Pas trop joyeux mais ça va mieux par rapport à hier. j'ai implémenté un autre algo pour la décompte du temps au niveau du serveur et ça a tendance à marcher plus ou moins. ça va pour l'instant. Je vais garder l'autre algo de timer que tu m'as filé au cas où un autre blème arrive de ce côté. Désormais j'ai le code qui suit pour la décompte du temps côté serveur:

Code:

int h=0,m=0;
        char hm[11]={0};
        while(temps!=0){

                div_t t;
                //...d'autres choses

                t=div(temps, 60);
                h=t.quot;
                m=t.rem;
                if(m==1)
                m=0;

                sprintf(hm,"%d:%d",h,m);
                sock_send_text(p->sock,hm);

                temps--;
                Sleep(1000);
        }
        sprintf(hm,"%d:%d",h,m);
        sock_send_text(p->sock,"FIN");

...et du côté client je le réceptionne de cette manière:

//Réception du temps restant envoyé par le serveur
Code:

char *reponse=sock_recv_text_dyn(sock);
                           
while(strcmp(reponse,"FIN")!=0 && strcmp(reponse,"0:0")!=0){

//...Autre chose

//Affichage du temps reçu
gtk_label_set_text(GTK_LABEL(hm_restantes),reponse);

free(reponse),reponse=NULL;

reponse=sock_recv_text_dyn(sock);

}
free(reponse),reponse=NULL;

Voilà pour ce côté, je te dirai quand j'aurai d'autres blèmes à propos (mais s'il ya un truc à dire sur le code tu peux toujours ... ;-) )

Bien! là, je continue avec mes questions sur les sockets et les threads.


- Côté client, le client peut décider d'arrêter(par exemple par un clic sur un bouton "arrêter l'heure") lui même la décompte du temps (que le serveur fait et lui envoie), comment puis je faire cette partie? peut-être envoyer aussi un message "FIN" comme le serveur le fait? Si oui, comment le serveur va t-il le réceptionner étant donné que depuis qu'il décompte l'heure, il est le seul à envoyer quelque chose. (NB: pendant la décompte, le client ne fait que réceptionner). Faut-il un thread supplémentaire? Si oui, merci de me guider.

Question en plus clair:

-Comment faire savoir ce désir du client au serveur pour qu'il tue le thread consacré à ce client (qui veut se déconnecter)?


STP essaie de te baser sur les 2 bouts de code ci-dessus pour me répondre.

Thanks!

trunks
Bavard
Bavard

Messages : 18
Date d'inscription : 06/11/2008

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  -ed- Mar 11 Nov 2008 - 20:15

trunks a écrit:Slt!
Pas trop joyeux mais ça va mieux par rapport à hier. j'ai implémenté un autre algo pour la décompte du temps au niveau du serveur et ça a tendance à marcher plus ou moins. ça va pour l'instant. Je vais garder l'autre algo de timer que tu m'as filé au cas où un autre blème arrive de ce côté. Désormais j'ai le code qui suit pour la décompte du temps côté serveur:

Code:

int h=0,m=0;
        char hm[11]={0};
        while(temps!=0){

                div_t t;
                //...d'autres choses

                t=div(temps, 60);
                h=t.quot;
                m=t.rem;
                if(m==1)
                m=0;

                sprintf(hm,"%d:%d",h,m);
                sock_send_text(p->sock,hm);

                temps--;
                Sleep(1000);
        }
        sprintf(hm,"%d:%d",h,m);
        sock_send_text(p->sock,"FIN");
C'est correct, mais pas précis, car aux 1000 ms de la suspension, il faut ajouter les temps de traitement et d'émission du bloc. C'est probablement négligeable, sauf si on est suspendu par le traitement d'autres threads...

Personnellement, j'aurais mis le décompteur chez le client. Inutile de consommer de la BP pour ça. En cas d'échéance, le client envoi une info...

D'une manière plus générale, je vois que tes commandes sont envoyées 'en vrac', c'est à dire sans délimiteur... C'est OK si le réseau est faiblement encombré et que le débit est faible, mais sauf si le protocole est de type question/réponse, il est possible de recevoir 2 commandes à la suite dans le même bloc,

"HELLOWORLD"

voire sur plusieurs blocs.

"HELLOW"
"ORLD"

Comment tu feras pour les séparer ?

Tu remarqueras que les protocole textes utilisent en général une marque de fin de ligne pour séparer les commandes :

Emission :
"HELLO\n"
"WORLD\n"

Même si on reçoit 'en vrac',

"HELLO\nW"
"ORLD\n"

on saura recoller les morceaux.


...et du côté client je le réceptionne de cette manière:

//Réception du temps restant envoyé par le serveur
Code:

char *reponse=sock_recv_text_dyn(sock);
                           
while(strcmp(reponse,"FIN")!=0 && strcmp(reponse,"0:0")!=0){

//...Autre chose

//Affichage du temps reçu
gtk_label_set_text(GTK_LABEL(hm_restantes),reponse);

free(reponse),reponse=NULL;

reponse=sock_recv_text_dyn(sock);

}
free(reponse),reponse=NULL;
OK, sous réserve de ce que j'ai dit au-dessus..

Bien! là, je continue avec mes questions sur les sockets et les threads.


- Côté client, le client peut décider d'arrêter(par exemple par un clic sur un bouton "arrêter l'heure") lui même la décompte du temps (que le serveur fait et lui envoie), comment puis je faire cette partie? peut-être envoyer aussi un message "FIN" comme le serveur le fait? Si oui, comment le serveur va t-il le réceptionner étant donné que depuis qu'il décompte l'heure, il est le seul à envoyer quelque chose. (NB: pendant la décompte, le client ne fait que réceptionner). Faut-il un thread supplémentaire? Si oui, merci de me guider.

Question en plus clair:

-Comment faire savoir ce désir du client au serveur pour qu'il tue le thread consacré à ce client (qui veut se déconnecter)?

Comme déjà dit :

- j'aurais pas mis la boucle de comptage sur le serveur, mais chez le client
- si tu y tiens, il faut que le serveur puisse recevoir en même temps, donc comme il faut un thread par fonction bloquante et que se sont Sleep() et recv(), je te laisse en tirer la conclusion qui s'impose...
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  trunks Mar 11 Nov 2008 - 20:39

C'est correct, mais pas précis, car aux 1000 ms de la suspension, il faut ajouter les temps de traitement et d'émission du bloc. C'est probablement négligeable, sauf si on est suspendu par le traitement d'autres threads...

Si je comprends bien, tu me conseilles alors d'ajouter plus que que 1000 ms en tenant compte du temps que prendront comme tu dis les temps de traitement et d'émission du bloc. c'est bien ça que tu dis? confirme seulement!


Personnellement, j'aurais mis le décompteur chez le client. Inutile de consommer de la BP pour ça. En cas d'échéance, le client envoi une info...

Donc tu penses que que tout serait plus simple si je mets la décompte du temps au niveau au niveau du client ? côté code je veux dire. Si oui, regarde si ce pseudo algo peut faire l'affaire.

-Le client après s'être connecté au serveur, lui demande de lui envoyer le temps.
-le client le prends(le temps), fait décompte et envoie le résultat au serveur qui le reprends à son tour et fait une sauvegarde dans la base.
- tout cela dans une boucle jusqu'à ce que le temps vaut 0 ou jusqu'à ce que le client d'arrêter tout ça.

C'est juste le raisonnement? quelque chose à ajouter ou à corriger sinon merci de me dire quoi faire alors si c'est le client qui décompte.


D'une manière plus générale, je vois que tes commandes sont envoyées 'en vrac', c'est à dire sans délimiteur... C'est OK si le réseau est faiblement encombré et que le débit est faible, mais sauf si le protocole est de type question/réponse, il est possible de recevoir 2 commandes à la suite dans le même bloc,
<...>

Euh... j'ai pas bien compris cette partie cette partie. le conseil final à tirer c'est quoi? c'est de mettre un \n à la fin des chaines que j'envoie?



- j'aurais pas mis la boucle de comptage sur le serveur, mais chez le client
- si tu y tiens, il faut que le serveur puisse recevoir en même temps, donc comme il faut un thread par fonction bloquante et que se sont Sleep() et recv(), je te laisse en tirer la conclusion qui s'impose...

Ok! dans ce cas je mets la décompte du côté client si ça peut faciliter certaines choses. Et à propos ma question dessus est là haut ;-)
A+

trunks
Bavard
Bavard

Messages : 18
Date d'inscription : 06/11/2008

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  -ed- Mar 11 Nov 2008 - 21:06

trunks a écrit:
C'est correct, mais pas précis, car aux 1000 ms de la suspension, il faut ajouter les temps de traitement et d'émission du bloc. C'est probablement négligeable, sauf si on est suspendu par le traitement d'autres threads...

Si je comprends bien, tu me conseilles alors d'ajouter plus que que 1000 ms en tenant compte du temps que prendront comme tu dis les temps de traitement et d'émission du bloc. c'est bien ça que tu dis? confirme seulement!
Non. Je dis que 1000 ms, est un minium garanti, mais que ça peut faire plus, voire beaucoup plus, c'est la conception qui est à revoir... Il vaut mieux s'appuyer sur des données temporelles stables comme time(). Je croyais l'avoir déjà indiqué...

Personnellement, j'aurais mis le décompteur chez le client. Inutile de consommer de la BP pour ça. En cas d'échéance, le client envoi une info...

Donc tu penses que que tout serait plus simple si je mets la décompte du temps au niveau au niveau du client ? côté code je veux dire. Si oui, regarde si ce pseudo algo peut faire l'affaire.

-Le client après s'être connecté au serveur, lui demande de lui envoyer le temps.
-le client le prends(le temps), fait décompte et envoie le résultat au serveur qui le reprends à son tour et fait une sauvegarde dans la base.
- tout cela dans une boucle jusqu'à ce que le temps vaut 0 ou jusqu'à ce que le client d'arrêter tout ça.

C'est juste le raisonnement? quelque chose à ajouter ou à corriger sinon merci de me dire quoi faire alors si c'est le client qui décompte.

OK.

D'une manière plus générale, je vois que tes commandes sont envoyées 'en vrac', c'est à dire sans délimiteur... C'est OK si le réseau est faiblement encombré et que le débit est faible, mais sauf si le protocole est de type question/réponse, il est possible de recevoir 2 commandes à la suite dans le même bloc,
<...>
Euh... j'ai pas bien compris cette partie cette partie. le conseil final à tirer c'est quoi? c'est de mettre un \n à la fin des chaines que j'envoie?
Oui. C'est le minimum pour un protocole 'texte'.

Ca permet, par la suite, si le besoin s'en fait sentir, de découper et de réassembler correctement les commandes reçues.
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  trunks Mer 12 Nov 2008 - 11:30

Non. Je dis que 1000 ms, est un minium garanti, mais que ça peut faire plus, voire beaucoup plus, c'est la conception qui est à revoir... Il vaut mieux s'appuyer sur des données temporelles stables comme time(). Je croyais l'avoir déjà indiqué...

Ok!


Euh... j'ai pas bien compris cette partie cette partie. le conseil final à tirer c'est quoi? c'est de mettre un \n à la fin des chaines que j'envoie?

Oui. C'est le minimum pour un protocole 'texte'.

Ca permet, par la suite, si le besoin s'en fait sentir, de découper et de réassembler correctement les commandes reçues.

- Puis je avoir un exemple concret sur ce point? Donc si je n'ajoute pas le \n comme tu dis, quand le réseau sera encombré, le données peuvent ne pas atteir correctement?
Un exemple où tu en mets et où tu recolles tout après à la réception!


-Au fait! et si parallèlement à ces histoires de décompte et d'envoi entre client et serveur(fait par un thread de chaque côté), je veux envoyer d'autres messages? je sais que tu vas me dire d'implémenter une autre thread des deux côtés pour s'en occuper mais j'aimerais savoir comment c'est possible? si oui ,comment le second thread du client saura que ce qu'il envoie au serveur sera réceptionné par le second thread du serveur. je considère dans ce la le premier thread comme le thread chargé de transporter la décompte du temps des deux côtés et le second thread celui destiné à d'autres messages parallèles.

trunks
Bavard
Bavard

Messages : 18
Date d'inscription : 06/11/2008

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  -ed- Mer 12 Nov 2008 - 13:25

trunks a écrit:
Euh... j'ai pas bien compris cette partie cette partie. le conseil final à tirer c'est quoi? c'est de mettre un \n à la fin des chaines que j'envoie?

Oui. C'est le minimum pour un protocole 'texte'.

Ca permet, par la suite, si le besoin s'en fait sentir, de découper et de réassembler correctement les commandes reçues.

- Puis je avoir un exemple concret sur ce point? Donc si je n'ajoute pas le \n comme tu dis, quand le réseau sera encombré, le données peuvent ne pas atteir correctement?
Un exemple où tu en mets et où tu recolles tout après à la réception!

http://mapage.noos.fr/emdel/clib.htm
Module REC

C'est du C un peu avancé (callback). Si tu ne comprends pas comment ça marche, je me fendrais peut être de quelques exemples, voire d'un mode d'emploi...

-Au fait! et si parallèlement à ces histoires de décompte et d'envoi entre client et serveur(fait par un thread de chaque côté), je veux envoyer d'autres messages? je sais que tu vas me dire d'implémenter une autre thread des deux côtés pour s'en occuper mais j'aimerais savoir comment c'est possible? si oui ,comment le second thread du client saura que ce qu'il envoie au serveur sera réceptionné par le second thread du serveur. je considère dans ce la le premier thread comme le thread chargé de transporter la décompte du temps des deux côtés et le second thread celui destiné à d'autres messages parallèles.
Il ne faut qu'un seul thread par connexion (recv() sur un socket donné). Ca n'aurait aucun sens de mettre 2 threads en réception sur le même socket. Le même thread sert à gérer tous les échanges. C'est pour ça que le protocole doit être clair, car il ne doit y avoir aucune ambiguïté sur les commandes et leurs paramètres.

C'est la première chose à définir avant de coder quoique ce soit...
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  trunks Mer 12 Nov 2008 - 20:30

Ok! je vais voir à quoi ressemble le lien que tu m'as donné. Une question qui pourrait beaucoup m'aider (encore plus).
Y a til un moyen pour savoir si un texte envoyé par send est bien arrivé à destination ou pas? (juste savoir si le texte a été réceptionné)

trunks
Bavard
Bavard

Messages : 18
Date d'inscription : 06/11/2008

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  -ed- Mer 12 Nov 2008 - 20:41

trunks a écrit:Ok! je vais voir à quoi ressemble le lien que tu m'as donné. Une question qui pourrait beaucoup m'aider (encore plus).
Y a til un moyen pour savoir si un texte envoyé par send est bien arrivé à destination ou pas? (juste savoir si le texte a été réceptionné)
Le send () est bloquant. EN TCP/IP, tant que n'en est pas sorti, c'est que la transmission n'a pas abouti. Si tu en sors avec une erreur (retour < 0) ou une déconnexion (retour = 0), c'est que la transmission n'a pas abouti. Sinon (retour > 0), la transmission a réussi, du moins au niveau IP.

Au-dessus, évidemment, on en sait rien. C'est le rôle du protocole applicatif de faire des acquittements si c'est jugé utile (en TCP, c'est probablement redondant, sauf données critiques, genre transfert de fichiers binaires).

En UDP/IP, par contre, c'est du 'send and forget'. L'acquittement applicatif est obligatoire, ne serait-ce que pour gérer la congestion...
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  trunks Mer 12 Nov 2008 - 22:38

Si j'ai bien compris Emdel, il suffit seulement de vérifier si la valeur retournée par send vaut 0. si oui alors le texte envoyé n'est pas envoyé. cool alors! je veux m'en servir par exemple pour arrêter la décompte de l'heure niveau serveur. un truc du genre, si le serveur envoie l'heure décompté au client et que la valeur de send vaut 0(donc client absent) alors arrêter la décompte..
C'est possible de faire ce controle avec send n'est ce pas? s'il faut me fier à ce que t'as dit.

Au fait, en ce qui concerne le fait de remettre la décompte du temps au niveau du client, mon pseudo algo proposé ne marche pas comme voulu etcomme je ne veux plus trop me casser la tête alors je vais garder la décompte au niveau du serveur (àmoins que t'es un algo à me proposer sur ce point)

trunks
Bavard
Bavard

Messages : 18
Date d'inscription : 06/11/2008

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  -ed- Jeu 13 Nov 2008 - 3:48

trunks a écrit:Si j'ai bien compris Emdel, il suffit seulement de vérifier si la valeur retournée par send vaut 0. si oui alors le texte envoyé n'est pas envoyé.
Non. Il faut tester <0 qui veut dire erreur et =0 qui veut dire deconnexion. >0 signifie OK, et encore, il faudrait vérifier que le valeur retournée (nombre d'octets émis) est bien égale à la valeur demandée (longueur des données), car sur certains systèmes, le découpage en trame doit être fait par l'application. Pour les petites trames de quelques centaines d'octets pas de problème A partir de 1000 environ, méfiance... Détails et algo sur mon site...
cool alors! je veux m'en servir par exemple pour arrêter la décompte de l'heure niveau serveur. un truc du genre, si le serveur envoie l'heure décompté au client et que la valeur de send vaut 0(donc client absent) alors arrêter la décompte..
C'est possible de faire ce controle avec send n'est ce pas? s'il faut me fier à ce que t'as dit.
Oui.
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  trunks Jeu 13 Nov 2008 - 11:33

Non. Il faut tester <0 qui veut dire erreur et =0 qui veut dire deconnexion. >0 signifie OK, et encore, il faudrait vérifier que le valeur retournée (nombre d'octets émis) est bien égale à la valeur demandée (longueur des données), car sur certains systèmes, le découpage en trame doit être fait par l'application. Pour les petites trames de quelques centaines d'octets pas de problème A partir de 1000 environ, méfiance... Détails et algo sur mon site...

D'accord c'est clair sur ce point. je vais alors m'en servir pour faire le controle pour voir si le client est déconnecté et arrêter ainsi la décompte. Thanks de ce côté.

http://mapage.noos.fr/emdel/clib.htm
Module REC

C'est du C un peu avancé (callback). Si tu ne comprends pas comment ça marche, je me fendrais peut être de quelques exemples, voire d'un mode d'emploi...

Ba ... bou! j'ai vu tes fonctions mais aucune idée sur comment m'en servir. Un exemple serait mieux pour piger tout ça. Puis-je en avoir?

Et puis c'est quand faut-il penser à assembler ce que j'ai reçu? Quel controle y a t-il à faire là-bas? Un bout de code please depuis un send() d'une appli A et d'un recv() d'un B suivi d'assemblage.

Concernant aussi ton algo de TIMER, voici ma traduction C.
Code:
int echeance=time(NULL)+temps;
do{
Sleep(1000);
//...certainscode ici...
}while(time(NULL)<echeance)

Vérifie si c'est OK! avec ça je nais plus besoin de décrémenter quoi ce soit n'est-ce pas(comme avant pour la valeur de temps).

trunks
Bavard
Bavard

Messages : 18
Date d'inscription : 06/11/2008

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  trunks Jeu 13 Nov 2008 - 11:37

Ah! désolé de n'avoir pas nettoyé les messages cités vers la bas de mon message.

trunks
Bavard
Bavard

Messages : 18
Date d'inscription : 06/11/2008

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  -ed- Jeu 13 Nov 2008 - 11:47

trunks a écrit:Ah! désolé de n'avoir pas nettoyé les messages cités vers la bas de mon message.
Tu ne vois pas un bouton problèmes généraux avec les sockets et les threads Icon_post_edit ?

C'est une vraie question. Etant admin, je vois ce bouton.
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  -ed- Jeu 13 Nov 2008 - 11:56

trunks a écrit:
http://mapage.noos.fr/emdel/clib.htm
Module REC

C'est du C un peu avancé (callback). Si tu ne comprends pas comment ça marche, je me fendrais peut être de quelques exemples, voire d'un mode d'emploi...

Ba ... bou! j'ai vu tes fonctions mais aucune idée sur comment m'en servir. Un exemple serait mieux pour piger tout ça. Puis-je en avoir?
Voici un exemple d'utilisation. Dois-je commenter ?
Code:

#include <stdio.h>

#include "ed/inc/rec.h"

void cb_trame (void *pData, sBUFSZ * pBuf)
{
  printf ("Trame recue : '%s'\n", pBuf->sz);
  BUFSZ_end (pBuf);
}

int main (void)
{
  static char const *as_sep[] = {
      "\n",
  };

  sREC_CFG cfg = {
      1024,
      1,
      as_sep,
      0, /* ne pas remonter le separateur */
  };

  sREC *rec = REC_init (&cfg);

  if (rec != NULL)
  {
      REC_installe_trame (rec, cb_trame, NULL);

      {
        sBUFSZ sz;
        BUFSZ_init (&sz, "Hel", MEM_STA);
        REC_assemble (rec, &sz);
      }

      {
        sBUFSZ sz;
        BUFSZ_init (&sz, "lo\nwo", MEM_STA);
        REC_assemble (rec, &sz);
      }

      {
        sBUFSZ sz;
        BUFSZ_init (&sz, "rld\n", MEM_STA);
        REC_assemble (rec, &sz);
      }

      REC_end (rec), rec = NULL;

  }

  return 0;
}

Et puis c'est quand faut-il penser à assembler ce que j'ai reçu? Quel controle y a t-il à faire là-bas? Un bout de code please depuis un send() d'une appli A et d'un recv() d'un B suivi d'assemblage.
après un recv(), bien sûr...

Concernant aussi ton algo de TIMER, voici ma traduction C.
Code:
int echeance=time(NULL)+temps;
do{
Sleep(1000);
//...certainscode ici...
}while(time(NULL)<echeance)

Vérifie si c'est OK! avec ça je nais plus besoin de décrémenter quoi ce soit n'est-ce pas(comme avant pour la valeur de temps).
Il ne faut rien mettre dans la boucle à part une suspension (sous Windows, Sleep()). 1000 veut dire 1000ms, soit une seconde. Quelle est l'ordre de grandeur de la suspension demandée ? En principe, on met une valeur de suspension 10 à 20 fois < à cette valeur pour avoir une précision correcte...
Code:

time_t echeance = time (NULL) + temps;
do
{
  Sleep (temps * 1000 / 20);
}
while (time(NULL) < echeance);
on fait l'hypothèse que 'temps' est en secondes, ce qui est vrai sur les systèmes conformes à POSIX.1 (et sur Windows).
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  trunks Jeu 13 Nov 2008 - 22:27

Voici un exemple d'utilisation. Dois-je commenter ?

Avant de penser à te demander de commenter ou pas, je vais y jeter calmement un coup d'oeil. je te tiens au courant.

après un recv(), bien sûr...
OK!

Il ne faut rien mettre dans la boucle à part une suspension (sous Windows, Sleep()). 1000 veut dire 1000ms, soit une seconde. Quelle est l'ordre de grandeur de la suspension demandée ? En principe, on met une valeur de suspension 10 à 20 fois < à cette valeur pour avoir une précision correcte...

Ok! l'ordre de grandeur d la suspension demandée dans mon cas est une minute donc 60.000 ms.

Si je ne dois rien mettre dans la boucle alors tout ce qui est censé se passer dans la boucle je le mets où? je le dis parce que c'est après la pause du timer que le serveur envoie a clitn son temps (décrémenté). et dans le cas de ce code de timer, temps représente le temps initial du serveur.

En fait le raisonnement est le suivant:

-Il a un temps de départ pour le client (par exemple 1 heure donc 60 min)
-Après que le programme fait une pause de 1 minutes (60.000 ms), il décrémente le temps de 1 puis l'envoie au client et ça reprend de nouveau. Si je ne dois rien mettre dans cette boucle alors les autres instruction resteront où?
A+

trunks
Bavard
Bavard

Messages : 18
Date d'inscription : 06/11/2008

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  -ed- Ven 14 Nov 2008 - 4:23

trunks a écrit:

Si je ne dois rien mettre dans la boucle alors tout ce qui est censé se passer dans la boucle je le mets où? je le dis parce que c'est après la pause du timer que le serveur envoie a clitn son temps (décrémenté). et dans le cas de ce code de timer, temps représente le temps initial du serveur.
Pour moi, c'est un thread indépendant qui ne sert qu'à déclencher un traitement à l'échéance. Le reste du traitement est fait ailleurs indépendamment (dans un autre thread).

-Il a un temps de départ pour le client (par exemple 1 heure donc 60 min)
-Après que le programme fait une pause de 1 minutes (60.000 ms), il décrémente le temps de 1 puis l'envoie au client et ça reprend de nouveau. Si je ne dois rien mettre dans cette boucle alors les autres instruction resteront où?
Instructions qui font quoi ? Il ne peut pas y avoir 2 fonctions bloquantes dans le même thread...
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

problèmes généraux avec les sockets et les threads Empty Re: problèmes généraux avec les sockets et les threads

Message  Contenu sponsorisé


Contenu sponsorisé


Revenir en haut Aller en bas

Page 1 sur 2 1, 2  Suivant

Revenir en haut

- Sujets similaires

 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum
Ne ratez plus aucun deal !
Abonnez-vous pour recevoir par notification une sélection des meilleurs deals chaque jour.
IgnorerAutoriser