S'enregistrer | Rechercher | FAQ | Liste des Membres | Groupes d'utilisateurs | Connexion

  Nom d'utilisateur:    Mot de passe:       

  

Poster un nouveau sujet   Répondre au sujet Page 1 sur 1
Voir le sujet précédent :: Voir le sujet suivant  
Auteur Message
MessagePosté le: Mar Mar 15, 2011 9:57 am    Sujet du message: [Winsock]Thread Recv/send non fonctionnel Répondre en citant

{RISEN}
Projets


 
Inscrit le: 28 Oct 2010
Messages: 14



Bonjour Ă  tous !

Me voilà encore une fois car je me suis lancé dans les sockets... Mais bien que l'envie soit la, je suis rebuté encore une fois par de détails :

1 - La thread qui s'occupe d'envoyer ou recevoir ne reçois ni envois rien...
2 - Si je met un recv/send après acceptation d'un nouveau client, cela fonctionne mais qu'une seule fois (alors que côté client, une boucle se charge d'envoyer tout le temps les infos)
3 - Je n'ai pas encore compris comment envoyez et recevoir sur la mĂŞme application... Une explication serais la bienvenue

Je sais que le code est dégueulasse et je m'en excuse... C'est un serveur/client de test dans le but de bien tout comprendre avant de me lancer dans un soft plus propre et plus générique... Mais pour ça il me faut bien comprendre tout son fonctionnement.

Un GROS merci à ceux qui pourrons répondre à mes questions !!

Code:
#define      MAX_CLIENTS 10
#include <fstream>
using namespace std;
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <winsock.h>
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"pthreadVC2.lib")
#include <pthread.h>
#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>
#include <errno.h>
#define PORT 55555

typedef struct ClientInfos
{
    int  ID;
    char User[32];
    char Password[32];
    char Name[200];
    int  IsRegister;
    int  Packet;
   int  Alive;
   int sayChat;
   char Chat[512];
   int nbrClients;
   int UseRefID;
}ClientInfos;
ClientInfos ClientInfo[30];

typedef struct Client
{

  SOCKET ClientSocket;

};
Client Client[MAX_CLIENTS];

SOCKET csock;
SOCKET sock;

int client=0;

pthread_t ThreadRecvAndSend;
void *Sync_Client(void *data);

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

    SOCKADDR_IN sin;

    int recsize = sizeof sin;

    int sock_err;

    if(!erreur)
    {
        sock = socket(AF_INET, SOCK_STREAM, 0);

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

            sin.sin_addr.s_addr = htonl(INADDR_ANY);
            sin.sin_family = AF_INET;
            sin.sin_port = htons(PORT);
            sock_err = bind(sock, (SOCKADDR*) &sin, recsize);

            if(sock_err != SOCKET_ERROR)
            {
                sock_err = listen(sock, 5);
                printf("Listage du port %d...\n", PORT);

                if(sock_err != SOCKET_ERROR)
                {
                    fd_set readfs;

                    while(1)
                    {
                        FD_ZERO(&readfs);
                        FD_SET(sock, &readfs);

                        if(select(sock + 1, &readfs, NULL, NULL, NULL) < 0)
                        {
                            perror("select()");
                            exit(errno);
                        }

                        if(FD_ISSET(sock, &readfs))
                        {                           
                            SOCKADDR_IN csin;
                            int crecsize = sizeof csin;
                            SOCKET csock = accept(sock, (SOCKADDR *) &csin, &crecsize);
                            printf("Un client s'est connecte\n");
                            pthread_create(&ThreadRecvAndSend, NULL, Sync_Client, NULL);
                            client++;
                        }
                    }
                }
            }
        }
    }

    #if defined (WIN32)
        WSACleanup();
    #endif

    return EXIT_SUCCESS;
}

void *Sync_Client(void *data)
{
   bool Connected = 1;
   while(Connected)
   {
       if(recv(csock, reinterpret_cast<char*>(&ClientInfo), sizeof(ClientInfo), 0) != SOCKET_ERROR)
       {
          printf("%s test\n", ClientInfo[1].User);
       }
       else if (send(csock, reinterpret_cast<char*>(&ClientInfo), sizeof(ClientInfo), 0) != SOCKET_ERROR)
       {
          printf("%s test\n", ClientInfo[1].User);
       }
       else Connected = false;
   }
}
Voir le profil de l'utilisateur Envoyer un message privés
MessagePosté le: Mar Mar 15, 2011 12:45 pm    Sujet du message: Répondre en citant

TorTukiTu
Site Admin


 
Inscrit le: 07 Fév 2008
Messages: 1960
Localisation: Devant son pc durant la redaction de ce message



Dieu du ciel, ce code est Ă  vomir...

C'est du C ou du CPP ?

Je n'insiterai pas sur les conneries et autres mochetées diverses et variées de ce code.

Le problème vient du fait que ton thread ne partage pas les mêmes variables que le processus père, et même si c'était le cas, tu vois bien qu'à chaque fois qu'un client se connecte, tu réinitialise ta variable csock.

La solution la plus simple est de passer ta variable csock comme argument de pthread_create.

Ce qui donne le code suivant:

Code:
#define      MAX_CLIENTS 10
//using namespace std;
#include <stdio.h>
#include <string.h>
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"pthreadVC2.lib")
#include <pthread.h>
#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>
#include <errno.h>
#define PORT 55555

typedef struct ClientInfos
{
    int  ID;
    char User[32];
    char Password[32];
    char Name[200];
    int  IsRegister;
    int  Packet;
   int  Alive;
   int sayChat;
   char Chat[512];
   int nbrClients;
   int UseRefID;
}ClientInfos;

typedef struct Client
{
  SOCKET ClientSocket;
};

Client Client[MAX_CLIENTS];
ClientInfos ClientInfo[30];

SOCKET csock;
SOCKET sock;

int client=0;

pthread_t ThreadRecvAndSend;
void *Sync_Client(void *data);

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

    SOCKADDR_IN sin;

    int recsize = sizeof sin;

    int sock_err;

    if(!erreur)
    {
        sock = socket(AF_INET, SOCK_STREAM, 0);

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

            sin.sin_addr.s_addr = htonl(INADDR_ANY);
            sin.sin_family = AF_INET;
            sin.sin_port = htons(PORT);
            sock_err = bind(sock, (SOCKADDR*) &sin, recsize);

            if(sock_err != SOCKET_ERROR)
            {
                sock_err = listen(sock, 5);
                printf("Listage du port %d...\n", PORT);

                if(sock_err != SOCKET_ERROR)
                {
                    fd_set readfs;

                    while(1)
                    {
                        FD_ZERO(&readfs);
                        FD_SET(sock, &readfs);

                        if(select(sock + 1, &readfs, NULL, NULL, NULL) < 0)
                        {
                            perror("select()");
                            exit(errno);
                        }

                        if(FD_ISSET(sock, &readfs))
                        {                           
                            SOCKADDR_IN csin;
                            int crecsize = sizeof csin;
                            SOCKET csock = accept(sock, (SOCKADDR *)&csin, (socklen_t *)&crecsize);
                            printf("Un client s'est connecte\n");
                            pthread_create(&ThreadRecvAndSend, NULL, Sync_Client, (void *)csock);
                            client++;
                        }
                    }
                }
            }
        }
    }

    #if defined (WIN32)
        WSACleanup();
    #endif

    return EXIT_SUCCESS;
}

void *Sync_Client(void *data)
{
  SOCKET csock = (SOCKET)data;
   bool Connected = 1;
   char * buffer[1024];
   while(Connected)
   {
       if(recv(csock, buffer, sizeof(ClientInfo), 0) != SOCKET_ERROR)
       {
    // ATTENTION ICI %s Affiche ta structure jusqu'Ă  ce que \0 (fin de chaine) soit rencontrĂ©e. Si \0 n'est pas dans la chaine envoyĂ©e par le client, le printf continuera a afficher la structure.
    // Tu dois donc t'assurer ici que seul les 32 chars de User seront affichĂ©s.
   
          printf("%s test\n", (( struct ClientInfos *)buffer)->User);
       }
       else if (send(csock, reinterpret_cast<char*>(&ClientInfo), sizeof(ClientInfo), 0) != SOCKET_ERROR)
       {
          printf("%s test\n", ClientInfo[1].User);
       }
       else Connected = false;
   }
}


Citation:
3 - Je n'ai pas encore compris comment envoyez et recevoir sur la mĂŞme application... Une explication serais la bienvenue


Si tu veux faire communiquer des processus et des threads entre eux, il faut que tu te rensigne sur ce que l'on appelle les IPC. [Inter Process Communication]

Envoyer un message à travers une socket vers une machine extérieure ou localement revient au même d'un point de vue programmaton. Pour communiquer avec toi-même, il faut que tu utilises localhost, soit l'ip (définie par standard) 127.0.0.1

Ensuite, il faut bien que tu comprennes ce qu'est un Thread, un Zombie, et d'une façon générale la gestion des processus par la machine. Il existe de très nombreux tutos sur le net pour ça.

Pour finir, RESPECTE LES CONVENTIONS. Si tu fais du C, compile avec gcc -Wall -pedantic -ansii

Si tu fais du C++, alors tu t'y tiens et tu fais de l'objet. Mais mixes pas les choses d'une façon aussi immonde. Je pense que ça montre à quel point tu es désordonné dans ta tête sur ce coup là... Si je peux te conseiller quelquechose, mets les choses au clair avec les normes et les conventions et recommence tout.

(Pour tester ton application, tu peux utiliser telnet pour simuler ton client ou netcat pour le coté serveur.)

La tortue du 974.
Voir le profil de l'utilisateur Envoyer un message privés Visiter le site web de l'utilisateur Compte AIM MSN Messenger Numéro ICQ
MessagePosté le: Mer Mar 16, 2011 1:45 pm    Sujet du message: Répondre en citant

{RISEN}
Projets


 
Inscrit le: 28 Oct 2010
Messages: 14



Citation:
Ensuite, il faut bien que tu comprennes ce qu'est un Thread, un Zombie, et d'une façon générale la gestion des processus par la machine. Il existe de très nombreux tutos sur le net pour ça.


C'est bien une fonction qui preux prendre x paramètres + initialisation de la thread, qui à la particularité d'être lue (voir répétée si dans une boucle ?-) en même temps que le programme sans bloquer celui-ci ?

Citation:
Pour finir, RESPECTE LES CONVENTIONS. Si tu fais du C, compile avec gcc -Wall -pedantic -ansii


Comme dis plus haut, j'ai pour habitude quand j'apprend une lib de faire un programme "chantier" me permettant de tester à l'arrache l'ensemble de possibilités. Mais j'admet que oser poster un code aussi dégueulasse... Étais carrément stupide

Citation:
Si tu veux faire communiquer des processus et des threads entre eux, il faut que tu te rensigne sur ce que l'on appelle les IPC. [Inter Process Communication]


En fait je ne pense que j'ai j'ai besoins de faire cela (dans un premier temps en tous cas). Pour faire simple, j'ai besoins que le serveur puisse récupérer en recv :

Code:
ClientInfo //Qui est une structure globale contenant les info DU client


puis :
Code:
OtherClientInfo[ClientInfo.ID]. ID //Chaque tableau du OtherClientInfo Ă©tant un client


Et enfin envoyer la structure globale OtherClientInfo à tous les clients... J'ai donc retenté l'experience :


Code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "memory.h"

#define SERVER_VERSION "0.4"

#ifdef WIN32
  #include <winsock2.h>
  #pragma comment(lib, "wsock32.lib")
  #pragma comment(lib, "pthreadVC2.lib")
#else
  #include <sys/socket.h>
  #include <sys/types.h>
  #include <resolv.h>
  #include <netdb.h>
  #define SOCKET int
#endif
#include <stdio.h>
#include <stdlib.h>

typedef struct ClientInfos
{
      int  ID;
      char User[32];
      char Password[32];
      char Name[32];
      int  IsRegister;
      int  Packet;
     int  Alive;
     int sayChat;
      char Chat[512];
     int nbrClients;
     int UseRefID;
}ClientInfos;
ClientInfos ClientInfo;

typedef struct OtherClientInfo
{
         int  ID;
       char User[32];
        char Password[32];
       char Name[32];
        int  IsRegister;
       int  Packet;
   int  Alive;
   int sayChat;
   char Chat[512];
   int nbrClients;
   int UseRefID;
}OtherClientInfo;
OtherClientInfo OtherClientInfos[30];

int CheckHandlerPacket()
{
         int id = ClientInfo.ID;
         char user[32];
         char password[32];
         char name[32];
         char chat[512];
         strcpy(user, ClientInfo.User);
         strcpy(OtherClientInfos[id].User, user);
         strcpy(name, ClientInfo.Name);
         strcpy(OtherClientInfos[id].Name, name);
         strcpy(password, ClientInfo.Password);
         strcpy(OtherClientInfos[id].Password, password);
         strcpy(chat, ClientInfo.Chat);
         strcpy(OtherClientInfos[id].Chat, chat);
         OtherClientInfos[id].ID = id;
         OtherClientInfos[id].IsRegister = ClientInfo.IsRegister;
         OtherClientInfos[id].Packet = ClientInfo.Packet;
         OtherClientInfos[id].Alive = ClientInfo.Alive;
         OtherClientInfos[id].sayChat = ClientInfo.sayChat;
         OtherClientInfos[id].UseRefID = ClientInfo.UseRefID;

   if(ClientInfo.Packet != 0)
   {
        switch(ClientInfo.Packet)
        {
            case 1: //Try yo login...
               printf("%s(%d) is login to the gameserver ...\n", ClientInfo.User, ClientInfo.ID);
            break;

            case 2://Using object sending to the other clients
              printf("%s(%d) use object with this refID : %x ...\n", ClientInfo.User, ClientInfo.ID, ClientInfo.UseRefID);
            break;

            case 3://Sending chat text
              printf("%s say : %s\n", ClientInfo.User, ClientInfo.Chat);
            break;

            default:
              printf("%s send bad packet(%d)", ClientInfo.User, ClientInfo.Packet);
            break;
        }
   }else return 0;

}

void * memoryAlloc(size_t sizeOfBlock)
{
     void * ptr = NULL;
     ptr = malloc(sizeOfBlock);

     if(ptr == NULL)
     {
        fprintf(stderr,"Allocation impossible \n");
        exit(EXIT_FAILURE);
     }
     return ptr;
}

void memoryFree(void * ptr)
{
     free(ptr);
     ptr = NULL;
}

typedef struct{
    SOCKET      sock;
    SOCKADDR_IN data;
    pthread_t   clientThread;
}socket_t;

int clientNumber = 0;

void * clientManager(socket_t * client)
{
      socket_t * mclient = client;
      char * buffer = NULL;
      char * clientBuffer = NULL;
      int i=1;

      pthread_detach(mclient->clientThread);
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
      pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

      buffer = memoryAlloc(sizeof(char) * 64);
      sprintf(buffer, "%s", inet_ntoa(mclient->data.sin_addr)); // on rĂ©cupère l'adresse du client
      printf("Client : %s - %i client(s) en ligne\n", buffer, clientNumber);
      clientBuffer = memoryAlloc(sizeof(char) * 1024);

      while(i)
      {
         recv(mclient->sock, &ClientInfo, sizeof(ClientInfo), 0);
         int id = ClientInfo.ID;


         if (ClientInfo.Packet != 0)
              CheckHandlerPacket();
          int try = send(mclient->sock, &OtherClientInfos, sizeof(OtherClientInfos), 0);
          OtherClientInfos[id].sayChat = 0;
          if(try == SOCKET_ERROR)
           {
                   memoryFree(clientBuffer);
                   shutdown(mclient->sock, 2);
                   clientNumber--;
                   printf("deconnection de %s - %i client(s) en ligne\n", buffer, clientNumber);
                   memoryFree(mclient);
                   memoryFree(buffer);
                   pthread_exit(0);
           }
        }


  return 0;
}

int main(int count, char **args)
{
      #ifdef WIN32
          WSADATA wsaData;
      #endif

      socket_t server;
      socket_t * client = NULL;
      int clientDataSize = sizeof(SOCKADDR_IN);

      #ifdef WIN32

      if (WSAStartup(MAKEWORD(2, 2), &wsaData))
          exit(EXIT_FAILURE);
          printf("Experimental Server v. %s\n  MS Windows version\n", SERVER_VERSION);
          printf("  * Winsock v%i.%i\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
      #else
          printf("Experimental Server v. 0.2\n  Unix version");
      #endif

      server.sock                 = socket(PF_INET, SOCK_STREAM, 0);
      server.data.sin_addr.s_addr = INADDR_ANY;
      server.data.sin_family      = AF_INET;
      server.data.sin_port        = htons(55555);

      bind(server.sock, (SOCKADDR *)&(server.data), sizeof(server.data));
      listen(server.sock, 0);

      while(1)
      {
          client = memoryAlloc(sizeof(socket_t));

         if((client->sock = accept(server.sock, (SOCKADDR *)&(client->data), &clientDataSize)) != INVALID_SOCKET)
         {
           clientNumber++;
           pthread_create(&(client->clientThread), 0, clientManager, client);
           client = NULL;
         }
     }
     return 0;
}



Mais ici, j'ai l'impression que le serveur n'envois que la structure globale OtherClientInfo du client et non celle de tout les clients ...

Dans tous les cas, merci pour ton intervention !
Voir le profil de l'utilisateur Envoyer un message privés
Poster un nouveau sujet   Répondre au sujet Page 1 sur 1

  


 
Sauter vers:  
Vous ne pouvez pas poster de nouveaux sujets dans ce forum
Vous ne pouvez pas répondre aux sujets dans ce forum
Vous ne pouvez pas éditer vos messages dans ce forum
Vous ne pouvez pas supprimer vos messages dans ce forum
Vous ne pouvez pas voter dans les sondages de ce forum



130344 Attacks blocked