TCP-sockets, server antwortet nicht auf client akzeptieren: interrupted system call

Bin ich versucht zu implementieren TCP-server und-client in C unter Solaris. Ich bin neu auf sockets und bin mit Beej ' s Guide als Beispiel.

Für den Anfang, was ich möchte, ist für den client zum senden einer Nachricht an den server in form von word1 word2. Nach Erhalt, ich möchte dem server zu extrahieren word2 aus der Nachricht und senden Sie dieses zurück an den client.

Den ersten client --> server-Nachricht senden, funktioniert einwandfrei. Aber der server --> client-Antwort funktioniert nicht. Es gibt mehrere Fehler-Symptome:

  1. Der server scheint nicht einmal versuchen, Sie zu send() nichts an den client.
  2. Nach Erhalt der client die Meldung, der server gibt: accept: Interrupted system call kehrt dann an die Spitze der while(1) Schleife und bleibt dort, bis ich Strg-C aus.
  3. Aufruf des Clients zu recv() gibt 0 bytes.

Fand ich einen alten thread hier, wo der Letzte post sagt:

akzeptieren wird unterbrochen von der Kind-Prozess ein signal zu senden zurück zu den Eltern, wenn es beendet wird (SIGCHLD, wenn ich nicht schreiben). Sie können entweder SIGCHLD ignorieren, oder Sie können code accept() zur Verarbeitung des interrupt-besser (errno auf EINTR)

Allerdings bin ich mir nicht, das zu verstehen. Warum wird der Kind-Prozess beenden, bevor Sie sogar versuchen, die send() Teil? Was bedeutet "Griff die interrupt-besser" bedeuten?

Suche nach etwas mehr, fand ich dieser Frage auf Stack Overflow: Wie behandeln EINTR (interrupted System Call).

Habe ich versucht, indem Sie den code in die akzeptierte Antwort, und ersetzen write() mit send(), aber ich sehe immer noch das gleiche Verhalten.

Server-code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <signal.h>

const char* nodename = "localhost";
const char* FILESERV1_LISTEN_PORT = "41063";
const unsigned int MAXDATASIZE = 100;

void sigchld_handler(int s)
{
//from http://beej.us/guide/bgnet/examples/server.c
    while(waitpid(-1, NULL, WNOHANG) > 0);
}

//get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
//from http://beej.us/guide/bgnet/examples/server.c
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(void)
{
    //from http://beej.us/guide/bgnet/examples/server.c
    int rv;
    const unsigned int BACKLOG = 3; //how many pending connections queue will hold
    int tcp_sockfd, new_tcp_sockfd;  //listen on tcp_sockfd, new connection on new_tcp_sockfd
    struct addrinfo fs_hints, *fileservinfo, *p_fsinfo;
    struct sockaddr_storage client_addr; //connector's address information
    socklen_t sin_size;
    struct sigaction sa;
    char yes='1'; //char for Solaris
    char s[INET6_ADDRSTRLEN];
    int tcp_numbytes, tcp_numbytes_written, size;
    char tcp_recv_buf[MAXDATASIZE];
    char *word1, *word2;

    memset(&fs_hints, 0, sizeof fs_hints);
    fs_hints.ai_family = AF_INET; //force IPv4
    fs_hints.ai_socktype = SOCK_STREAM;
    //fs_hints.ai_flags = AI_PASSIVE; //use my IP

    if ((rv = getaddrinfo(nodename, FILESERV1_LISTEN_PORT, &fs_hints, &fileservinfo)) != 0) {
        fprintf(stderr, "file_server1: getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    //loop through all the results and bind to the first we can
    for(p_fsinfo = fileservinfo; p_fsinfo != NULL; p_fsinfo = p_fsinfo->ai_next) {
        if ((tcp_sockfd = socket(p_fsinfo->ai_family, p_fsinfo->ai_socktype,
                p_fsinfo->ai_protocol)) == -1) {
            perror("file_server1: socket");
            continue;
        }

        if (setsockopt(tcp_sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                sizeof(int)) == -1) {
            perror("file_server1: setsockopt");
            exit(1);
        }

        if (bind(tcp_sockfd, p_fsinfo->ai_addr, p_fsinfo->ai_addrlen) == -1) {
            close(tcp_sockfd);
            perror("file_server1: bind");
            continue;
        }

        break;
    }

    if (p_fsinfo == NULL)  {
        fprintf(stderr, "file_server1: failed to bind\n");
        return 2;
    }

    freeaddrinfo(fileservinfo); //all done with this structure

    if (listen(tcp_sockfd, BACKLOG) == -1) {
        perror("file_server1: listen");
        exit(1);
    }

    sa.sa_handler = sigchld_handler; //reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("file_server1: sigaction");
        exit(1);
    }

    printf("DEBUG: file_server1: waiting for connections...\n");

    //signal(SIGCHLD, SIG_IGN);  /* now I don't have to wait()! */

    while(1) {  //main accept() loop
        printf("DEBUG: Top of while loop\n");
        sin_size = sizeof client_addr;
        new_tcp_sockfd = accept(tcp_sockfd, (struct sockaddr *)&client_addr, &sin_size);
        if (new_tcp_sockfd == -1) {
            perror("file_server1: accept");
            continue;
        }

        inet_ntop(client_addr.ss_family, get_in_addr((struct sockaddr *)&client_addr), s, sizeof s);
        printf("DEBUG: file_server1: got connection from %s\n", s);

        if (!fork()) { //this is the child process
            printf("DEBUG: inside if\n");
            close(tcp_sockfd); //child doesn't need the listener
            if ((tcp_numbytes = recv(new_tcp_sockfd, tcp_recv_buf, MAXDATASIZE-1, 0)) == -1) {
                perror("file_server1: recv");
                exit(1);
            }
            tcp_recv_buf[tcp_numbytes] = '\0';
            printf("DEBUG: file_server1: received: %s\n", tcp_recv_buf);

            sscanf(tcp_recv_buf, "%s %s", word1, word2);
            printf("DEBUG: file_server received word1: %s and word2: %s.\n", word1, word2);

            size = strlen(word2);
            while (size > 0) {
                printf("DEBUG: top of inner while size\n");
                tcp_numbytes_written = send(new_tcp_sockfd, word2, strlen(word2), 0);
                if (tcp_numbytes_written == -1) {
                    if (errno == EINTR) {
                        printf("DEBUG: continuing after EINTR\n");
                        continue;
                    }
                    else {
                        printf("DEBUG: -1 on send(), not EINTR\n");
                        perror("DEBUG: file_server1: send");
                        return -1;
                    }
                }
                word2 += tcp_numbytes_written;
                size -= tcp_numbytes_written;
                printf("DEBUG: bottom of inner while size\n");
            }
            printf("DEBUG: file_server has sent %s to client.\n", word2);
            close(new_tcp_sockfd);
            //exit(0);
        }
        printf("DEBUG: outside of if\n");
        close(new_tcp_sockfd);  //parent doesn't need this
        printf("DEBUG: Bottom of while loop\n");
    }

    return 0;
}

Client-code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

const char* nodename = "localhost";
const char* FILESERV1_LISTEN_PORT = "41063";
const unsigned int MAXDATASIZE = 100; //max number of bytes we can get at once

//get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    //http://beej.us/guide/bgnet/examples/client.c
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(void)
{
    //from http://beej.us/guide/bgnet/examples/client.c
    int tcp_sockfd, tcp_numbytes;
    char buf[MAXDATASIZE];
    struct addrinfo fs_hints, *fileservinfo, *p_fsinfo;
    struct sockaddr_storage my_addr; //for storing local dynamic port number
    unsigned short int client_tcp_port;
    char client_ipaddr_str[INET_ADDRSTRLEN];
    socklen_t addrlen;
    int rv;
    int getsock_check;
    char fs_ipaddr_str[INET6_ADDRSTRLEN];

    char *msg_to_send = "abcdef hijklm"; //word1 and word2

    memset(&fs_hints, 0, sizeof fs_hints);
    fs_hints.ai_family = AF_INET; //IPv4
    fs_hints.ai_socktype = SOCK_STREAM;

    if ((rv = getaddrinfo(nodename, FILESERV1_LISTEN_PORT, &fs_hints, &fileservinfo)) != 0) {
        fprintf(stderr, "client1: getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    //loop through all the results and connect to the first we can
    for(p_fsinfo = fileservinfo; p_fsinfo != NULL; p_fsinfo = p_fsinfo->ai_next) {
        if ((tcp_sockfd = socket(p_fsinfo->ai_family, p_fsinfo->ai_socktype, p_fsinfo->ai_protocol)) == -1) {
            perror("client1: socket");
            continue;
        }

        if (connect(tcp_sockfd, p_fsinfo->ai_addr, p_fsinfo->ai_addrlen) == -1) {
            close(tcp_sockfd);
            perror("client1: connect");
            continue;
        }

        break;
    }
    printf("DEBUG: client1: socket and connect successful\n");
    if (p_fsinfo == NULL) {
        fprintf(stderr, "client1: failed to connect\n");
        return 2;
    }

    addrlen = sizeof my_addr;
    if ((getsock_check=getsockname(tcp_sockfd, (struct sockaddr *)&my_addr, (socklen_t *)&addrlen)) == -1) { 
        perror("client1: getsockname");
        exit(1);
    }
    printf("DEBUG: client1: getsockname successful\n");
    client_tcp_port = ntohs(((struct sockaddr_in *)&my_addr)->sin_port);
    inet_ntop(AF_INET, &(((struct sockaddr_in *)&my_addr)->sin_addr), client_ipaddr_str, INET_ADDRSTRLEN);
    printf("DEBUG: client1 has dynamic TCP port number %hu and IP address %s.\n", client_tcp_port, client_ipaddr_str);

    inet_ntop(p_fsinfo->ai_family, get_in_addr((struct sockaddr *)p_fsinfo->ai_addr), fs_ipaddr_str, sizeof fs_ipaddr_str);
    printf("DEBUG: client1: connecting to %s\n", fs_ipaddr_str);
    freeaddrinfo(fileservinfo); //all done with this structure

    if (send(tcp_sockfd, msg_to_send, strlen(msg_to_send), 0) == -1) {
        perror("client1: send");
        exit(1);
    }

    printf("DEBUG: The request from client1 has been sent to the file_server1\n");

    if ((tcp_numbytes = recv(tcp_sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
        perror("client1: recv");
        exit(1);
    }

    buf[tcp_numbytes] = '\0';

    printf("DEBUG: client1: received %d bytes, content '%s'\n", tcp_numbytes, buf);
    close(tcp_sockfd);


    return 0;
}

Ausgabe vom server:

DEBUG: file_server1: waiting for connections...
DEBUG: Top of while loop
DEBUG: file_server1: got connection from 127.0.0.1
DEBUG: outside of if
DEBUG: Bottom of while loop
DEBUG: Top of while loop
DEBUG: inside if
DEBUG: file_server1: received: abcdef hijklm
file_server1: accept: Interrupted system call
DEBUG: Top of while loop

Ausgabe client:

DEBUG: client1: socket and connect successful
DEBUG: client1: getsockname successful
DEBUG: client1 has dynamic TCP port number 51196 and IP address 127.0.0.1.
DEBUG: client1: connecting to 127.0.0.1
DEBUG: The request from client1 has been sent to the file_server1
DEBUG: client1: received 0 bytes, content ''

Schließlich, ich will schließlich, dass dieser server mit den gleichen 2-Wege-Transaktion mit einem möglichen zweiten oder Dritten client (für jetzt, nicht conerned mit gleichzeitig betreute Kunden). Will ich halten, das sockfd zurückgegeben listen() öffnen Sie in dieser situation?

  • Interrupted system call passieren, wenn ein signal ankommt, während des Wartens stat der server, die Zeit die spezifizierte signal ignoriert wird. Versuchen Sie, Griff EINTR signal
InformationsquelleAutor tony_tiger | 2013-11-19
Schreibe einen Kommentar