Shymaxtic
Shymaxtic

Reputation: 37

Non-blocking Linux server socket

I want to create a server socket that always prints to screen "tick" , and if one client sends data to this server, the server will print that data. I use non-blocking socket, but the it does not work, server prints to screen "tick" but cannot receives data from client.

Server

int main(int argc, char *argv[]) {
    int server_sockfd, client_sockfd;
    sockaddr_un server_address;
    sockaddr_un client_address;
    int client_len;
    int res;

    /* remove old socket and create unnamed socket */
    unlink("server_socket");
    server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);

    /* non-blocking socket */
    fcntl(server_sockfd, F_SETFL, O_NONBLOCK);

    /* name the socket */
    server_address.sun_family = AF_UNIX;
    strcpy(server_address.sun_path, "server_socket");
    bind(server_sockfd, (sockaddr*)&server_address, sizeof(server_address));

    /* listen client */
    printf("server_waiting\n");
    listen(server_sockfd, 5);
    client_len = sizeof(client_address);
    client_sockfd = accept(server_sockfd, (sockaddr*)&client_address, (socklen_t*)&client_len);

    while(1) {
        char ch;
        res = recv(client_sockfd, &ch, 1, 0);
        if (res == -1) {
            printf("tick\n");
        }
        else {
            printf("received: %c\n", ch);
        }
    }    
}

client

int main(int argc, char *argv[]) {
    int sock_fd;
    struct sockaddr_un address;
    int result;
    char ch = 'A';

    /* create socket for client */
    sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);

    /* name of socket as agreed with server */
    address.sun_family = AF_UNIX;
    strcpy(address.sun_path, "server_socket");

    result = connect(sock_fd, (sockaddr*) &address, sizeof(address));
    if (result == -1) {
            perror("fail\n");
            exit(1);
    }

    /* write via socket */
    send(sock_fd, &ch, 1, 0);
    close(sock_fd);
    exit(0);
}

Upvotes: 1

Views: 3286

Answers (1)

Soren
Soren

Reputation: 14688

You are setting the listing socket to be non-blocking instead of the accepted socket.

Following your code logic, you DO want to wait on the accept call, but not the recv call

Instead of

/* non-blocking socket */
fcntl(server_sockfd, F_SETFL, O_NONBLOCK);

Delete it and instead add the fcntl call to the socket you are getting back from the accept call, like

client_sockfd = accept(....);
int flags = fcntl(client_sockfd, F_GETFL, 0);
fcntl(client_sockfd, F_SETFL, flags | O_NONBLOCK);

accept and fcntl can fail so you should check for failures in production code.

Upvotes: 3

Related Questions