Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 12
  1. #1
    Utente di HTML.it
    Registrato dal
    Sep 2008
    Messaggi
    101

    [C]read bloccante nella comunicazione client/server tcp

    Il programma dovrebbe mandare un messaggio da client al server(multi thread per gestire più clienti) che a sua volta dovrebbe stamparlo.Il problema è che una volta inviato il messaggio la read del server entra nello stato bloccante non arrivando mai al printf("Sono fuori").
    La situazione cambia quando avvio un nuovo client mantenendo aperti il server e il vecchio client perchè una volta che si connette la read si "sblocca".


    Codice Client
    codice:
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #define N 256
    int main(int argc, char *argv[]) {
    int c_fd,portno,lung,abba;
    struct sockaddr_in sin;
    struct hostent *hp;
    char buffer[N];
    	if (argc != 3) {
    		printf("Illegal number of arguments");
    		exit(1);
    	}
    	if ((hp = gethostbyname(argv[1])) == 0) {
    		perror("tom: gethostbyname");
    		exit(1);
    	}
    	c_fd = socket(AF_INET, SOCK_STREAM, 0);
    	portno = atoi(argv[2]);
    	sin.sin_family = AF_INET;
    	memcpy((char *)&sin.sin_addr,(char *)hp->h_addr,hp->h_length);
    	sin.sin_port = htons(portno);
    	if(connect(c_fd, (struct sockaddr *) &sin, sizeof(sin)) < 0){
    		printf("connect() failed\n");
    		return 1;
    	}
    	printf("(CLIENT) Scrivere un messaggio: "); 
    fgets(buffer,N,stdin);
    
    	write(c_fd, buffer,strlen(buffer));
    	printf("Client %d ha inviato il messaggio\n", getpid());
    	close(c_fd);
    	return 0;
    }//end client


    codice Server(per compilarlo con il terminale unix per via dei thread)
    gcc nomefile.c -o nomeeseguibile -lpthread

    codice:
    #include<errno.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<pthread.h>
    #include<netinet/in.h>
    #include<netdb.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #define N 256
    void *gestisci(void *arg) {
            int a;
    	printf("gestisci(): creato il thread\n");
    	char buf[N];
    	while(a=read((int *) arg, buf, N)!=0)
           {
    
             if(a==-1)
              perror("\nerrore\n");
     	else
    	printf("\nServer %s   finito\n\n", buf);
    	}
    printf("sono fuori");
    	close((int *) arg);
    	pthread_exit (0);
    }
    
    
    int main(int argc, char *argv[]){
    int s_fd, c_fd, portno, len;
    pthread_t tid;
    char buffer[N];
    struct sockaddr_in sin, client;
    	s_fd=socket(AF_INET,SOCK_STREAM,0);
    	portno = atoi(argv[1]);
    	sin.sin_family = AF_INET;
    	sin.sin_port = htons(portno);
    	sin.sin_addr.s_addr = htonl(INADDR_ANY);
    	len = sizeof(client);
    	bind(s_fd, (struct sockaddr *) &sin, sizeof(sin));
    	listen(s_fd,5);
    	while (1){
    		c_fd = accept(s_fd,(struct sockaddr *)&client, &len);
    		inet_ntop(AF_INET,&client.sin_addr,buffer,sizeof(buffer));
    		printf("Request from client %s\n",buffer);
    		pthread_create(&tid,NULL,gestisci,(void *)c_fd);
    		pthread_detach(tid);//serve per liberare risorse
    	}
    	close(s_fd);
    	return 0;
    }//end server

  2. #2
    Utente di HTML.it
    Registrato dal
    Sep 2011
    Messaggi
    9
    Ciao a primo occhio ci sono degli errori sulla funzione gestisci per il semplice motivo che non azzeri il buffer ad ogni iterazione è per questo che la read si blocca poi è meglio utilizzare la funzione recv per ricevere è piu stabile. prova cosi:
    codice:
    void * gestisci(int socket)
    {
    #define size 1024
    char buffer[size];
    /*in caso che la funzione venga richiamata piu volte azzero il buffer prima di iniziare la iterazione con il ciclo */
    
    memset(buffer,0,sizeof(buffer));
    while(1)
    {
    int ricevuto=recv(socket,buffer,sizeof(buffer),0);
    printf("byte:%d Server:%s",ricevuto,buffer);
    //in caso che ricevo il messaggio quit terminto il ciclo e continuo la funzione.
    if(strcmp(buffer,"quit")==0)
    break;
    memset(buffer,0,sizeof(buffer));
    }
    printf("sono fuori");
    	close(socket);
    	pthread_exit (0);
    
    }
    non ho provato il codice lo fatto in 5 minuti cmq dovrebbe andare. ciao

  3. #3
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    Il problema della stampa di "sono fuori" è dovuto probabilmente al mancato flush del buffer di stdout. Aggiungi un '\n' alla stringa oppure chiama fflush(stdout) subito dopo la printf().

    Fai attenzione anche a questa istruzione:

    codice:
    while (a = read((int *) arg, buf, N) != 0) {
    tieni presente che l'operatore relazionale != ha priorità maggiore rispetto a quello di assegnazione =, pertanto alla variabile "a" non stai assegnando il valore di ritorno della read() per poi confrontarlo con 0, ma stai assegnando il valore 0/non0 del risultato del confronto read(...) != 0.
    every day above ground is a good one

  4. #4
    Utente di HTML.it
    Registrato dal
    Sep 2008
    Messaggi
    101
    nè fflush nè l'altra soluzione hanno funzionato la read rimane sempre in modalità bloccante.

    tieni presente che l'operatore relazionale != ha priorità maggiore rispetto a quello di assegnazione =, pertanto alla variabile "a" non stai assegnando il valore di ritorno della read() per poi confrontarlo con 0, ma stai assegnando il valore 0/non0 del risultato del confronto read(...) != 0.
    Ho provato a cambiare anche la priorità dell'assegnazione sperando che fosse quello il problema ma purtroppo non ho risolto.
    codice:
    while ((a = read((int *) arg, buf, N) )!= 0) {
    Oltre ciò se provo a stampare il buffer per più di 2 volte il programma va incontro ad un errore di segmentazione.

  5. #5
    Utente di HTML.it
    Registrato dal
    Sep 2011
    Messaggi
    9
    Fammi capire una cosa hai provato il codice che ti ho postato?secoda cosa se non funziona modificalo mettendo il fflush(stdout) ad ogni printf es:
    codice:
     printf("prova");fflush(stdout);
    dimmi se funziona. un altra cosa ai detto che la read va in stato bloccante.... nella funzione che ti ho modificato ho messo la funzione recv al posto della read perché e piu affidabile.

  6. #6
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    Posta il codice che hai adesso con le modifiche indicate.
    every day above ground is a good one

  7. #7
    Utente di HTML.it
    Registrato dal
    Sep 2011
    Messaggi
    9
    Lo sistemato e lo testato funziona alla perfezione diciamo che sembra una chat anzi è una chat ... ecco il codice che ho sistemato :

    Server:
    codice:
    //
    //  main.c
    //  server
    //
    //  Created by GHIRO9 on 30/08/12.
    //  Copyright (c) 2012 GHIRO9. All rights reserved.
    //
    
    #include<errno.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<pthread.h>
    #include<netinet/in.h>
    #include<netdb.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #define N 256
    void *gestisci(void *socket) {
    	printf("gestisci(): creato il thread\n");
    	char buf[N];
    	    while (1) {
           ssize_t byte=0;
            
            if((byte=recv((int)socket, buf, sizeof(buf), 0))!=-1)
            {
                
                printf("Dati ricevuti: %s\n",buf);fflush(stdout);
             
                if (strcmp(buf, "quit\n")==0) {
                    
                    memset(buf, 0, sizeof(buf));
                    break;
                    
                }
                memset(buf, 0, sizeof(buf));
            }
            else{
                perror("errore ricezzione\n");fflush(stdout);
                
                
            }
            
            
        
        }
        
        printf("sono fuori\n");fflush(stdout);
    	close((int)socket);
    	pthread_exit (0);
    }
    
    
    int main(int argc, char *argv[]){
        int s_fd, c_fd, portno;
        socklen_t len;
        pthread_t tid;
        char buffer[N];
        struct sockaddr_in sin, client;
    	s_fd=socket(AF_INET,SOCK_STREAM,0);
    	portno = atoi(argv[1]);
    	sin.sin_family = AF_INET;
    	sin.sin_port = htons(portno);
    	sin.sin_addr.s_addr = htonl(INADDR_ANY);
    	len = sizeof(client);
    	bind(s_fd, (struct sockaddr *) &sin, sizeof(sin));
    	listen(s_fd,5);
    	while (1){
    		c_fd = accept(s_fd,(struct sockaddr *)&client, &len);
    		inet_ntop(AF_INET,&client.sin_addr,buffer,sizeof(buffer));
    		printf("Request from client %s\n",buffer);
    		pthread_create(&tid,NULL,gestisci,(void *)c_fd);
    		pthread_detach(tid);//serve per liberare risorse
    	}
    	close(s_fd);
    	return 0;
    }//end server
    questo è il client:

    codice:
    //
    //  main.c
    //  client
    //
    //  Created by GHIRO9 on 30/08/12.
    //  Copyright (c) 2012 GHIRO9. All rights reserved.
    //
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #define N 256
    
    
        int main(int argc, char *argv[]) {
            int c_fd,portno,lung,abba;
            struct sockaddr_in sin;
            struct hostent *hp;
            char buffer[N];
            if (argc != 3) {
                printf("Illegal number of arguments");
                exit(1);
            }
            if ((hp = gethostbyname(argv[1])) == 0) {
                perror("tom: gethostbyname");
                exit(1);
            }
            c_fd = socket(AF_INET, SOCK_STREAM, 0);
            portno=atoi(argv[2]);
            sin.sin_family = AF_INET;
            memcpy((char *)&sin.sin_addr, (char *)hp->h_addr, hp->h_length);
            sin.sin_port = htons(portno);
    	if(connect(c_fd, (struct sockaddr *) &sin, sizeof(sin)) < 0){
            perror("connect");
    		
    		return 1;
    	}
        while (1) {
            printf("(CLIENT) Scrivere un messaggio: ");
            fgets(buffer,N,stdin);
    
        
        if((send(c_fd, buffer, strlen(buffer), 0))!=-1)
        {
            printf("Messaggio inviato");
            
        }
        else{
            
            perror("send");
        }
        }
        
    	
        return 0;
        
    
        
        
    }//end client

  8. #8
    Utente di HTML.it
    Registrato dal
    Sep 2008
    Messaggi
    101
    Grazie a tutti.Mi ero impuntato sulla write e sulla read(come dalle slide da cui studiavo).Il programma funziona perfettamente ed inoltre ho capito anche altre cose utili.
    Dato che queste conoscenze le utilizzerò per un progetto riguardante un corso di Sistemi Operativi in cui dobbiamo utilizzare le System call di basso livello mi confermate che anche send e recv lo sono?

  9. #9
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    Se dai il comando "man syscalls" ottieni un elenco completo di tutte le system calls Linux.
    every day above ground is a good one

  10. #10
    Utente di HTML.it
    Registrato dal
    Sep 2011
    Messaggi
    9
    Originariamente inviato da Zanzy
    Grazie a tutti.Mi ero impuntato sulla write e sulla read(come dalle slide da cui studiavo).Il programma funziona perfettamente ed inoltre ho capito anche altre cose utili.
    Dato che queste conoscenze le utilizzerò per un progetto riguardante un corso di Sistemi Operativi in cui dobbiamo utilizzare le System call di basso livello mi confermate che anche send e recv lo sono?
    Come ti è gia stato detto da YuYevon con quel comando ti permette la visione delle chiamate di sistema di unix, cmq per esperienza personale è meglio utilizzare le chiamate a send e recv per maggiore stabilita nella trasmissione dei dati.... se hai ulteriori domande chiedi pure infine hai risolto con il sorgente che ti ho modificato ?

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.