简体   繁体   English

C TCP套接字:套接字上的read()返回资源暂时不可用

[英]C TCP sockets: read () on socket returns Resourse temporarily unavailable

The system I realize consists of a ring of tokens (each token is a ckient-server process). 我实现的系统由一个令牌环组成(每个令牌是一个ckient-server进程)。

I tested it runnimy two processes. 我通过两个过程对其进行了测试。

In function serverMessageProcessor() I call readMessage() function, in which I use read() to read all parts of a message from an (in)socket and (after processes it) write another message on (out)socket. 在功能serverMessageProcessor()我请readMessage()函数,其中,我使用read()从一个(上)套接字中读取的消息的所有部分和(进程之后)写上(下)套筒的另一消息。

The first time I do it, it works well, the second time, one of the read() function in my readMessage() function, gives read: Success (I use perror to catch read error) and read: Resourse temporarily unavailable on the other process. 第一次,它运行良好,第二次,我的readMessage()函数中的read()函数之一给出read: Success (我使用perror捕获读取错误),并read: Resourse temporarily unavailable在服务器上read: Resourse temporarily unavailable其他过程。

There are some prints for debugging in the code. 代码中有一些用于调试的打印件。 I hope you can help me. 我希望你能帮助我。 Thanks a lot in advance. 非常感谢。

#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;
}

When read() returns 0 , it means the socket has been closed by the other end, it's not an error, so you shouldn't call sys_error() . read()返回0 ,表示套接字已被另一端关闭,这不是错误,因此您不应调用sys_error() An error is indicated by read() returning -1 . read()返回-1表示错误。 That's why you're getting Success as the error message. 这就是为什么您将“ Success作为错误消息。

However, you've set the socket to be non-blocking, so read() will also return -1 when there's nothing available to be read. 但是,您已将套接字设置为非阻塞,因此当没有可读取的内容时, read()也会返回-1 It will set errno = EAGAIN in this case, and the message for this is Resource temporarily Available . 在这种情况下,它将设置errno = EAGAIN ,并且此消息为Resource temporarily Available You need to test for this and go back to your loop that waits for data with select() . 您需要对此进行测试,然后返回使用select()等待数据的循环。 This is normal for non-blocking sockets, so you shouldn't report it as an error. 这对于非阻塞套接字是正常的,因此您不应将其报告为错误。

So the code should be like: 因此,代码应类似于:

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

I've changed this to return -2 in the EAGAIN case, you'll need to change the caller to check for this so it doesn't call sys_error either. 我已将其更改为在EAGAIN情况下返回-2 ,您需要更改调用方以进行检查,因此它也不会调用sys_error

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM