2017-04-08 59 views
0

我實現該系統由令牌環(各令牌是ckient服務器進程)的。ÇTCP套接字:讀()套接字返回國土資源暫時不可用

我測試了它runnimy兩個過程。

在功能serverMessageProcessor()我請readMessage()功能,其中我使用read()從一個(上)套接字中讀取的消息的所有部分和(工序後話)寫上(下)套筒的另一消息。

我第一次做到這一點,它工作得很好,第二次,我readMessage()功能read()功能之一,給人read: Success(我用perror趕上讀取錯誤)和read: Resourse temporarily unavailable對其它過程。

有在代碼調試的一些版畫。 我希望你能幫助我。 非常感謝。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <sys/socket.h>  //per le funzioni sui socket. 
#include <arpa/inet.h>  //per la funzione inet_aton(). 
#include <netinet/in.h>  //per la struct sockaddr. 
#include <sys/wait.h> 
#include <signal.h> 
#include <sys/types.h> 
#include <sys/time.h> 
#include <ctype.h>   //per la funzione isdigit(). 
#include <fcntl.h>   //per rendere il socket bloccante o no. 
#include <sys/select.h> 

/* Error hendler */ 
void sys_error (const char *message) { 
    perror (message); 
} 


/* Connessione in ingresso */ 
int setUpConnectionIn(int port, int *sock_fd){ 
    int sock_in; 
    struct sockaddr_in addr; 


    addr.sin_family = AF_INET;     //Internet Address Family. 
    addr.sin_port=htons(port);     //Local port. 
    addr.sin_addr.s_addr = htonl(INADDR_ANY); //Any incoming interface. 

    //Create socket for incoming connections. 
    if((sock_in = socket(PF_INET, SOCK_STREAM, 0)) < 0) { 
     stampaStr("Errore: Creazione socket non riuscita.", 1); 
     return -1; 
    } 

    //Bind to the local address. 
    if(bind(sock_in, (struct sockaddr *) &addr, sizeof(addr)) < 0){ 
     sys_error("Errore: impossibile assegnare l'indirizzo al socket."); 
     close(sock_in); 
     return -1; 
    } 

    //Mark the socket so it will listen for incoming connections. 
    if(listen(sock_in,5) < 0) { 
     sys_error("Errore: listen non riuscita."); 
     close(sock_in); 
     return -1; 
    } 

    *sock_fd = sock_in; 

    return 0; 
} 

/* Interfaccia Connessione in ingresso */ 
int setUpConnectionIn_2 (int sock_fd){ 
    int connection_in; 


    if ((connection_in = accept(sock_fd, NULL, NULL)) < 0) { 
     sys_error ("Errore in funzione setUpConnectionIn_2"); 
     return -1; 
    } 


    return connection_in; 
} 

/* Connessione in uscita */ 
int setUpConnectionOut (int *sock_fd, int connection_port, char *conn_addr){ 
    int check; 
    struct sockaddr_in addr_out; 
    int sock_out; 
    addr_out.sin_family = AF_INET; 
    addr_out.sin_port = htons(connection_port); 

    if (inet_aton(conn_addr, &addr_out.sin_addr) < 0) { 
     sys_error ("Errore: inet_aton"); 
     return -1; 
    } 


    if((sock_out = socket(PF_INET, SOCK_STREAM, 0))<0) { 
     sys_error("Errore: Creazione socket non riuscita."); 
     return -1; 
    } 

    stampaStr("In attesa di connessione alla stazione successiva..\n", 1); 
    while(connect(sock_out, (struct sockaddr *)&addr_out, sizeof(addr_out)) < 0); 

    *sock_fd = sock_out; 

    return 0; 
} 

int closed_ring = 0; 

int readMessage (int *fd, unsigned char *cod, int *size, char **content) { 
    char *content_msg; 
    unsigned char cod_msg; 
    int size_msg; 

    int retval = fcntl(*fd, F_SETFL, fcntl(*fd, F_GETFL) | O_NONBLOCK); 

    printf ("readMessage - prima read\n"); 

    if (read(*fd, &cod_msg, 1) == 0) { 
     sys_error ("read - cod_msg"); 
     return -1; 
    } 

    if (read(*fd, &size_msg, 4) == 0) { 
     sys_error ("read - size_msg"); 
     return -1; 
    } 

    *content = (char *)malloc((size_msg+1)*sizeof(char)); 
    (*content)[size_msg+1] = '\0'; 
    if (read(*fd, *content, size_msg) == 0) { 
     sys_error ("read - content_msg"); 
     return -1; 
    } 

    retval = fcntl(*fd, F_SETFL, (fcntl(*fd, F_GETFL) | O_NONBLOCK) & (~O_NONBLOCK)); 

    printf ("readMessage - dopo read\n"); 
    printf ("(readMessage)cod: %c - size: %d - msg: %s\n", cod_msg, size_msg, *content); 
    *cod = cod_msg; 
    *size = size_msg; 
    //content = (char *)malloc(size_msg*sizeof(char)); 
    //memcpy(content, content_msg, strlen(content_msg)); 
    //content = content_msg; 
    printf ("content: %s\n", *content); 
    return 0; 
} 

int buildMessage (char **new_msg, unsigned char cod, int size, char *content) { 
    int msg_len = size+6; 
    *new_msg = (char *)malloc(msg_len*sizeof(char)); 
    (*new_msg)[0] = cod; 
    memcpy (((*new_msg)+1), &size, 4); 
    memcpy (((*new_msg)+5), content, size); 
    (*new_msg)[msg_len] = '\0'; 

    //new_msg = msg; 
    return strlen (*new_msg); 
} 

int serverMessageProcessor (int *fd_in, int *out_fds) { 
    char *new_msg; 
    char *content_msg; 
    unsigned char cod_msg = 100; 
    int size_msg; 
    int msg_length; 
    char *tmp_PID_str; 
    uint64_t myPID; 
    uint64_t tempPID; 
    int fd; 

    if (readMessage (fd_in, &cod_msg, &size_msg, &content_msg) < 0) { 
     sys_error ("readMessage"); 
     return -1; 
    } 

    printf ("(serverMessageProcessor) cod: %c - size: %d - msg: %s\n", cod_msg, size_msg, content_msg); 

    printf ("serverMessageProcessor - prima switch\n"); 
    switch (cod_msg) { 
     case ('1'): { 
      fd = 0; 
      if ((myPID = getpid()) < 0) { 
       sys_error ("getpid"); 
       return -1; 
      } 

      tmp_PID_str = (char *)malloc((size_msg+1)*sizeof(char)); 
      tmp_PID_str[size_msg+1] = '\0'; 
      printf ("serverMessageProcessor - prima memcpy(myPID) PID: %ld\n", myPID); 
      memcpy (tmp_PID_str, &myPID, sizeof(uint64_t)); 
      printf ("serverMessageProcessor - dopo memcpy(myPID)\n"); 

      if (strcmp (content_msg, tmp_PID_str) == 0) { 
       printf ("serverMessageProcessor - dopo strcmp TRUE (myPID, tempPID)\n"); 
       closed_ring = 1; 
      } else { 
       //new_msg = (char *)malloc(size_msg+6)*sizeof(char)); 
       printf ("serverMessageProcessor - dopo strcmp FALSE (myPID, tempPID)\n"); 
       //msg_length = buildMessage (&new_msg, cod_msg, size_msg, content_msg); 
       msg_length = size_msg+6; 
       new_msg = (char *)malloc(msg_length*sizeof(char)); 
       new_msg[0] = cod_msg; 
       memcpy (new_msg+1, &size_msg, 4); 
       memcpy (new_msg+5, content_msg, size_msg); 
       new_msg[msg_length] = '\0'; 
       printf ("serverMessageProcessor - dopo buildMessage: %s\n", new_msg); 

       printf ("(serverMessageProcessor) cod: %c - size: %d - msg: %s\n", cod_msg, size_msg, content_msg); 

       if (write (out_fds[fd], &cod_msg, 1) < 0) { 
        sys_error ("write"); 
        return -1; 
       } 

       if (write (out_fds[fd], &size_msg, 4) < 0) { 
        sys_error ("write"); 
        return -1; 
       } 

       if (write (out_fds[fd], content_msg, size_msg) < 0) { 
        sys_error ("write"); 
        return -1; 
       } 

       printf ("serverMessageProcessor - dopo write\n"); 
      } 

      printf ("serverMessageProcessor - fuori if strcmp(myPID, tempPID)\n"); 
     } 
    } 
} 

int main (int argc, char *argv[]) { 
    int listen_port, connection_port; 
    int connection; 
    int check = -1; 
    char *conn_addr; 
    char inter_lv = 'a'; 
    int sock_in; //socket descriptor for reading. 
    int sock_out; //socket descriptor for writing. 
    struct sockaddr_in addr_in; 
    struct sockaddr_in addr_out; 

    int connection_flag = 0; 
    int out_fds[3]; 
    /********************* VARIABILI GESTIONE MESSAGGI ************************/ 
    char *new_msg = NULL; 
    char *content_msg = NULL; 
    unsigned char cod_msg; 
    int size_msg; 
    int msg_len; 
    uint64_t tempPID; 
    uint64_t myPID; 
    /**************************************************************************/ 

    /********************** VARIABILI GESTIONE SOTTOPROCESSI ******************/ 
    int pipe_IN[2]; 
    int pipe_OUT[2]; 
    int pipe_CLIENT[2]; 
    int pid_client; 
    /**************************************************************************/ 

    /***************************** VARIABILI PER SELECT SYSCALL ***************/ 
    fd_set rfds; 
    struct timeval tv; 
    int retval; 
    /**************************************************************************/ 

    if(readIntFromString(0, &listen_port, argv[1]) < 0){ 
     printf("Invalid value of listen_port\n"); 
     return -1; 
    } 

    if(listen_port >= 0 && listen_port <= 1023){ 
     printf("Insert a port in range 0-1023\n"); 
     return -1; 
    } 

    if(listen_port >= 49152){ 
     printf("Insert a port not higher than 49152\n"); 
     return -1; 
    } 

    if(readIntFromString(0, &connection_port, argv[2]) < 0){ 
     printf("Invalid value of connection_port\n"); 
     return -1; 
    } 

    if(connection_port >= 0 && connection_port <= 1023){ 
     printf("Insert a port in range 0-1023\n"); 
     return -1; 
    } 

    if(connection_port >= 49152){ 
     printf("Insert a port not higher than 49152\n"); 
     return -1; 
    } 

    conn_addr = argv[3];   

    if((toupper(argv[4][0]) == 'S' || toupper(argv[4][0]) == 'N') && argv[4][1] == '\0'){ 
     inter_lv = toupper(argv[4][0]); 
    }else{ 
     printf("Invalid Interactivity Level\n"); 
     return -1; 
    } 


    /*********************** Circuit Building **************************/ 


    if(setUpConnectionIn(listen_port, &sock_in) < 0) { 
     sys_error ("Errore in funzione: setUpConnectionIn"); 
     return -1; 
    } 

    if (setUpConnectionOut (&sock_out, connection_port, conn_addr) < 0) { 
     sys_error ("Errore in funzione setUpConnectionOut"); 
     return -1; 
    } 

    printf ("-------------out-connected-------------\n"); 

    if ((connection = setUpConnectionIn_2 (sock_in)) < 0) { 
     sys_error ("Errore in funzione setUpConnectionIn_2"); 
     return -1; 
    } 

    printf ("-------------in-connected--------------\n"); 

    /**********************************************************************/ 

    /* Controlla connection (socket in entrata) per vedere se è pronto per operazioni di I/O */ 
    //retval = fcntl(connection, F_SETFL, fcntl(connection, F_GETFL) | O_NONBLOCK); 
    FD_ZERO(&rfds); 
    FD_SET(connection, &rfds); 

    out_fds[0] = sock_out; 
    /* Attende 5 secondi */ 

    tv.tv_sec = 5; 
    tv.tv_usec = 0; 

    while (closed_ring == 0) { 
     if (connection_flag == 0) { 
      if ((myPID = getpid()) < 0) { 
       sys_error ("getpid"); 
       return -1; 
      } 

      size_msg = sizeof(uint64_t); 
      msg_len = size_msg+6; 
      new_msg = (char*)malloc(msg_len*sizeof(char)); 

      new_msg[0] = '1'; 
      memcpy(new_msg+1, &size_msg, 4); 
      memcpy(new_msg+5, &myPID, size_msg); 
      new_msg[msg_len] = '\0'; 

      printf ("(MAIN) myPID: %ld - cod: %c - size: %d - msg: %s\n", myPID, new_msg[0], size_msg, &(new_msg[5])); 

      if (write (out_fds[0], new_msg, msg_len) < 0) { 
       sys_error ("write"); 
       return -1; 
      } 

      printf ("Message 1 (ring closing) sent: %s\n", new_msg); 
      connection_flag = 1; 
     } 

     retval = select(connection+1, &rfds, NULL, NULL, &tv); 

     if (retval == -1) { 
      sys_error ("select"); 
      return -1; 
     } else if (retval) { 
      stampaStr("Available data on (in)socket\n", 1); /* FD_ISSET(0, &rfds) avrà valore TRUE */ 

      /*************** DEBUG ************************ 
      if (read (connection, &cod_msg, 1) == 0) { 
       sys_error ("read - main"); 
       return -1; 
      } else { 
       printf ("read - main: %c\n", cod_msg); 
      } 
      **********************************************/ 
      if (serverMessageProcessor (&connection, out_fds) < 0) { 
       sys_error ("serverMessageProcessor"); 
       return -1; 
      } 
     } else { 
      stampaStr("None message in entry\n", 1); 
      char c = getchar(); 
      fflush(stdin); 
     } 
    } 


    /* Creazione sottoprocesso per gestione connessioni con Client per iscrizione auto */ 
    if (pipe(pipe_CLIENT) < 0) { 
     sys_error ("pipe_client"); 
     return -1; 
    } 

    if ((pid_client = fork()) < 0) { 
     sys_error ("fork_client"); 
     return -1; 
    } else if (pid_client == 0) { /* Processo figlio - accetta connessioni da Client */ 
     printf("Subprocess to manage client(s) connection\n"); 
     //while (1); 
    } else { /* Processo Padre */ 
     printf("Parent process\n"); 
    } 



    return 0; 
} 

回答

-1

read()回報0,這意味着套接字已被另一端關閉,這是不是一個錯誤,所以你不應該叫sys_error()read()返回-1表示錯誤。這就是爲什麼你會收到Success作爲錯誤信息。

但是,您已將套接字設置爲非阻塞,因此read()也將返回-1,因爲沒有可讀取的內容。在這種情況下,它將設置errno = EAGAIN,並且此消息爲Resource temporarily Available。 你需要測試這一點,並返回到你的循環與select()數據等待。這對於非阻塞套接字是正常的,所以您不應該將其報告爲錯誤。

因此,代碼應該是這樣的:

if (read(*fd, &cod_msg, 1) == -1) { 
    if (errno == EAGAIN) { 
     return -2; 
    } else { 
     sys_error ("read - cod_msg"); 
     return -1; 
    } 
} 

我已經改變了這個在EAGAIN的情況下返回-2,你需要修改調用檢查此所以它不叫sys_error無論是。

+1

這並不意味着套接字已被關閉。這意味着對方乾淨地斷開連接。該應用程序仍然需要關閉套接字。 EAGAIN的一個簡單的解決方案是使用阻塞模式,而不是試圖用另一個'select()'調用,另一個循環等來模擬它。 – EJP

+0

我已經修改了代碼,但是它會返回資源暫時不可用的錯誤,但不是成功「錯誤」。 – user7836391

+0

@EJP我的意思是說它已經被另一端關閉了。 – Barmar