kus3000 | Bonjour,
J'ai un problème de threads sous linux ubuntu 9.04.
Je code en C avec la bibliothèque <sys/socket.h>.
Avant de poster le code j'explique mon probleme :
Je dois réaliser un module de gestion de message (HTTP/TCP), et je me place entre un serveur S et un client C.
J'utilise LibCurl pour quelques étapes.
L'étape 1 consiste à réceptionner une requete HTTP de C
L'étape 2 consiste à la renvoyer à S.
S nous répond, on réceptionne la requette et on la relance a C.
Dans le principe, c'est simple. Mais l'on reçoit une cinquantaine de requete HTTP de C,
donc l'emploi des threads s'impose, et là c'est le drame (corruption de mémoire, etc.)
Il faut savoir que si je met les threads en mode JOIN, le programme marche !
Mais le but est bien entendu de lancer les 50 threads d'un coup, pas l'un a la suite de l'autre.
Voici la partie principale du code :
Code :
- if((socket_server = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
- {
- printf("Socket creation error !\n" );
- return EXIT_FAILURE;
- }
- // nous : on écoute sur le port HTTP (80) en local
- sockaddr_server.sin_family = AF_INET;
- sockaddr_server.sin_port = htons(80);
- sockaddr_server.sin_addr.s_addr = inet_addr("127.0.0.1" );
- server_len = sizeof(sockaddr_server);
- client_len = sizeof(sockaddr_client);
- if(setsockopt(socket_server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
- printf("setsockopt" );
- return EXIT_FAILURE;
- }
- if(bind(socket_server, (struct sockaddr*)&sockaddr_server, server_len) < 0)
- {
- printf("Socket bind error !\n" );
- return EXIT_FAILURE;
- }
- if(listen(socket_server, 10) != 0)
- {
- printf("Socket listen error !\n" );
- return EXIT_FAILURE;
- }
- int bEnd = 0;
- int iThreadNumber = 1;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
- while(bEnd == 0)//boucle infinie pour le moment
- {
- printf("[~]Waiting connection... \n" );
- socket_client = accept(socket_server, (struct sockaddr*)&sockaddr_client, (socklen_t *)&client_len);
- if(socket_client > 0)
- {
- printf("Recu une connection... socket %i\n",socket_client);
- printf("IP du client : %s\n",inet_ntoa(sockaddr_client.sin_addr));
- printf("Port du client : %i\n",ntohs(sockaddr_client.sin_port));
- time(&date);
- printf("[!]Established connection at %s\n", ctime(&date));
- // reception du paquet HTTP
- nbOctects = 0;
- memset(requestHTTP,0,MAX_RECEPT);
- if( (nbOctects = read(socket_client, &requestHTTP, MAX_RECEPT)) < 0)
- {
- printf("Socket recv error !" );
- return EXIT_FAILURE;
- }
- requestHTTP[nbOctects] = '\0';
- printf("\n" );
- printf("ETAPE 1 : Requete HTTP entière : (%d octects)\n", nbOctects);
- //printf("%s\n", requestHTTP);
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Gestion des threads :
- ex = (struct infosThread *)malloc(sizeof(struct infosThread));
- memset(ex,0,sizeof(struct infosThread));
- if(ex!=NULL)
- {
- memcpy(&(ex->iSocketTCPClient),&socket_client, sizeof(socket_client));
- memcpy(&(ex->iSizeRequetteHTTP),&nbOctects, sizeof(nbOctects));
- memcpy(&(ex->iThreadNumber),&iThreadNumber, sizeof(iThreadNumber));
- ex->cRequetteHTTP = (char *)malloc(sizeof(char) * nbOctects);
- memcpy(ex->cRequetteHTTP,requestHTTP, nbOctects);
- ex->cRequetteHTTP[nbOctects]='\0';
- }else{
- printf("probleme structure declaration\n" );
- }
- //lancement de la thread (etape 2 a finale)
- printf("\n" );
- printf(" --------------------------------------------- \n" );
- printf(" LANCEMENT THREAD NUMERO %i sur socket %i\n",iThreadNumber,ex->iSocketTCPClient);
- pthread_t thread;
- usleep(10); // 10 ms
- rc = pthread_create(&thread, &attr, print_message_function, (void *)ex);
- if(rc != 0)
- {
- printf ("pthread_create error for thread\n" );
- exit(0);
- }
- else
- {
- iThreadNumber++;//thread suivante
- }
- if(ex->cRequetteHTTP !=NULL){
- free(ex->cRequetteHTTP);
- ex->cRequetteHTTP= NULL;
- }
- if(ex!=NULL){
- free(ex);
- ex=NULL;
- }
- }
- }
|
Voici la fonction threadée :
Code :
- void * print_message_function( void *ptr )
- {
- char * requestHTTP = NULL;
- // récupération des données :
- int iSocketTCPClient = 0;
- int iSizeRequetteHTTP = 0;
- int iThreadNumber = 0;
- memcpy(&iSocketTCPClient,&(((struct infosThread *)(ptr))->iSocketTCPClient), sizeof(int));
- memcpy(&iSizeRequetteHTTP,&(((struct infosThread *)(ptr))->iSizeRequetteHTTP), sizeof(int));
- memcpy(&iThreadNumber,&(((struct infosThread *)(ptr))->iThreadNumber), sizeof(int));
- printf("iSocketTCPClient : %i\n",iSocketTCPClient);
- printf("iSizeRequetteHTTP : %i\n",iSizeRequetteHTTP);
- printf("iThreadNumber : %i\n",iThreadNumber);
- // PARFOIS iSocketTCPClient = 0 ! BUG !
- if(iSocketTCPClient > 0 && iSizeRequetteHTTP >0 && iThreadNumber >0)
- {
- requestHTTP = (char *)malloc(iSizeRequetteHTTP);// ici ça change la taille du ptr
- memset(requestHTTP,0,iSizeRequetteHTTP);
- memcpy(requestHTTP,((struct infosThread *)(ptr))->cRequetteHTTP,iSizeRequetteHTTP);
- requestHTTP[iSizeRequetteHTTP] = '\0';
- printf("taille : %i taille : %i taille:%i\n",iSizeRequetteHTTP,strlen(requestHTTP),strlen(((struct infosThread *)(ptr))->cRequetteHTTP));
- printf("cRequetteHTTP :\n %s ",requestHTTP);
- /////////////////////////////////////////////////////////////////////////////////////
- //autres variables : (gestion des fichiers temporaires suivant les threads)
- char REQUEST_HTTP_THREAD[40]="";
- char RESPONSE_THREAD[40]="";
- sprintf(REQUEST_HTTP_THREAD,"thread_%i_1_requetteHTTP",iThreadNumber);
- sprintf(RESPONSE_THREAD,"thread_%i_2_reponse",iThreadNumber);
- /////////////////////
- // lancer le processus :
- printf("etape2\n" );
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // ETAPE 2 : renvoyer la requete vers les serveurs
- CURL *curl = NULL;
- CURLcode res = 0;
- int sockfd = 0;
- size_t iolen = 0;
- curl = curl_easy_init();
- if(curl)
- {
- // ici on met l'IP du server
- curl_easy_setopt(curl, CURLOPT_URL, IP_SERVER);
- // Do not do the transfer - only connect to host
- curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
- res = curl_easy_perform(curl);
- if(CURLE_OK != res)
- {
- printf("Error: %s\n", strerror(res));
- //return 1;
- }
- // Extract the socket from the curl handle - we'll need it for waiting
- res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockfd);
- //int flags = fcntl (sockfd, F_GETFL);
- //fcntl (sockfd, F_SETFL, flags | O_NONBLOCK);
- if(res != CURLE_OK)
- {
- printf("Error: %s\n", strerror(res));
- //return 1;
- }
- // wait for the socket to become ready for sending
- if(!wait_on_socket(sockfd, 0, 10000L))
- {
- printf("Error: timeout.\n" );
- //return 1;
- }
- printf("Sending request (thread(%i)) from TV to Server\n",iThreadNumber);
- // sauvegarde de la requete dans un fichier :
- FILE * pRequestHTTP = fopen(REQUEST_HTTP_THREAD, "wb" );
- if(pRequestHTTP)
- {
- fwrite(requestHTTP,1,iSizeRequetteHTTP,pRequestHTTP);
- fclose(pRequestHTTP);
- }//
- // Send the requestHTTP. Real applications should check the iolen to see if all the request has been sent
- res = curl_easy_send(curl, requestHTTP, strlen(requestHTTP), &iolen);
- if(res != CURLE_OK)
- {
- printf("Error: %s\n", strerror(res));
- exit(1);
- //return 1;
- }
- printf("Reading response (thread(%i)) from Server.\n",iThreadNumber);
- printf("etape3\n" );
- ////////////////////////////////////////////////////
- // ETAPE 3 : récupérer la réponse du serveur
- int iPart = 0;
- FILE * pReponse = fopen (RESPONSE_THREAD,"wb" );
- char buf[MAX_RECEPT]="";
- memset(buf,0,MAX_RECEPT);
- if(pReponse)
- {
- for(;;)
- {
- wait_on_socket(sockfd, 1, 500L);
- res = curl_easy_recv(curl, buf, MAX_RECEPT, &iolen);
- fwrite(buf,1,iolen,pReponse);// en binaire !!!!!
- memset(buf,0,MAX_RECEPT);
- if(res != CURLE_OK){ break; }
- iPart++;
- }
- ////////////////////////////////////////////////////
- fclose (pReponse);
- }
- else{
- printf("impossible d'ouvrir %s\n",RESPONSE_THREAD);
- }
- printf("Reading response (thread(%i)) from Server DONE !.\n",iThreadNumber);
- curl_easy_cleanup(curl);
- }
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////
- printf("etape Finale\n" );
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // ETAPE FINALE
- char * cBody = NULL;
- int nbOctects = 0;
- FILE * pBodyfileRead = fopen (RESPONSE_THREAD,"rb" );
- // obtain file size:
- fseek (pBodyfileRead , 0 , SEEK_END);
- long lSize = ftell (pBodyfileRead);
- rewind (pBodyfileRead);
- // allocate memory to contain the whole file:
- cBody= (char*) malloc (sizeof(char)*lSize);
- memset(cBody,0,sizeof(char)*lSize);
- if (cBody== NULL) {fputs ("Memory error",stderr); exit (2);}
- // copy the file into the buffer:
- int result = fread (cBody,1,lSize,pBodyfileRead);
- cBody[lSize] = '\0';
- if (result != lSize) {fputs ("Reading error",stderr); exit (3);}
- //pthread_mutex_lock (&my_mutex);
- // cBodycontiennent les informations a renvoyer a la box
- // on renvoie a la netgem box tv du départ :
- //int flags = fcntl (iSocketTCPClient, F_GETFL);
- //fcntl (iSocketTCPClient, F_SETFL, flags | O_NONBLOCK);
- if( (nbOctects = write(iSocketTCPClient, cBody, lSize)) < 0)
- {
- printf("Socket send error !" );
- return (void *)EXIT_FAILURE;
- }
- else
- {
- printf("etape finale (thread(%i)): %i envoyés\n", iThreadNumber, nbOctects);
- /*
- struct timeval to;
- fd_set myset;
-
- to.tv_sec = 0;
- to.tv_usec =0; //microseconde
-
- FD_ZERO(&myset);
- FD_SET(iSocketTCPClient,&myset);
-
- if(select(iSocketTCPClient+1,&myset,NULL,&myset,&to) == 1){
- printf("EVENEMENT !\n" );
- return (void *)-1;
- }
- */
- }
- fclose(pBodyfileRead);
- if(cBody!=NULL){
- free(cBody);
- cBody=NULL;
- }
- /////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Nettoyage de sockets et des pointeurs :
- remove(REQUEST_HTTP_THREAD);
- remove(RESPONSE_THREAD);
- }
- printf("Close sockets (thread(%i))\n",iThreadNumber);
- int iCheckSocketClosedClient = close(iSocketTCPClient);
- iSocketTCPClient=-1;
- printf("Check state of sockets (0 is OK) : Client : %i\n", iCheckSocketClosedClient);
- if(requestHTTP!=NULL){
- free(requestHTTP);
- requestHTTP=NULL;
- }
- printf(" FIN THREAD NUMERO %i\n",iThreadNumber);
- printf(" --------------------------------------------- \n" );
- printf("\n" );
- pthread_exit ((void *)0);
- }
|
|