[Winsock]Thread Recv/send non fonctionnel

Moderator: Mod

[Winsock]Thread Recv/send non fonctionnel

Postby {RISEN} » Tue Mar 15, 2011 9:57 am

[b:e612dce47f]Bonjour à tous ![/b:e612dce47f]

[i:e612dce47f]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 :[/i:e612dce47f]

[b:e612dce47f]1 -[/b:e612dce47f] La thread qui s'occupe d'envoyer ou recevoir ne reçois ni envois rien...
[b:e612dce47f]2 -[/b:e612dce47f] 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)
[b:e612dce47f]3 -[/b:e612dce47f] 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.

[i:e612dce47f]Un[/i:e612dce47f] [b:e612dce47f]GROS[/b:e612dce47f] [i:e612dce47f]merci à ceux qui pourrons répondre à mes questions !![/i:e612dce47f]

[code:1:e612dce47f]#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;
}
}[/code:1:e612dce47f]
{RISEN}
Projets
 
Posts: 14
Joined: Thu Oct 28, 2010 6:02 am

Postby TorTukiTu » Tue Mar 15, 2011 12:45 pm

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:1:55074ddff2]#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;
}
}[/code:1:55074ddff2]

[quote:55074ddff2]3 - Je n'ai pas encore compris comment envoyez et recevoir sur la même application... Une explication serais la bienvenue [/quote:55074ddff2]

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.
User avatar
TorTukiTu
Site Admin
 
Posts: 1960
Joined: Thu Feb 07, 2008 10:24 pm
Location: Devant son pc durant la redaction de ce message

Postby {RISEN} » Wed Mar 16, 2011 1:45 pm

[quote:f0e560a0ee]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. [/quote:f0e560a0ee]

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 ?

[quote:f0e560a0ee]Pour finir, RESPECTE LES CONVENTIONS. Si tu fais du C, compile avec gcc -Wall -pedantic -ansii [/quote:f0e560a0ee]

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

[quote:f0e560a0ee]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] [/quote:f0e560a0ee]

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:1:f0e560a0ee]ClientInfo //Qui est une structure globale contenant les info DU client[/code:1:f0e560a0ee]

puis : [code:1:f0e560a0ee]OtherClientInfo[ClientInfo.ID]. ID //Chaque tableau du OtherClientInfo étant un client[/code:1:f0e560a0ee]

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


[code:1:f0e560a0ee]#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;
}

[/code:1:f0e560a0ee]

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 !
{RISEN}
Projets
 
Posts: 14
Joined: Thu Oct 28, 2010 6:02 am


Return to C/C++

Who is online

Users browsing this forum: No registered users and 1 guest

cron