Search code examples
cmultithreadingsocketsdeadlockblocking

Issue using c sockets with threads to read from and write to the socket


I want to write a TCP server-client chat, but when I start the two threads for reading from and writing to a socket at both sides, I think they block each other out. Can anyone help me with this?

Server Code:

/* A simple server in the internet domain using TCP the port number is passed as an argument */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>

struct server_args_runner{
    char buffer [256];
    int newsockfd;
    pthread_t tid;
    pthread_attr_t attr;
    //read/write attribute (read == 0 and write == 1)
        int rw;
};

void error(char *msg){
        perror(msg);
        exit(1);
}

void* server_runner_fun(void* args){
    // this is the chat part!
    // get args:
    int n;
    struct server_args_runner *sar = (struct server_args_runner*) args;
    if(sar->rw == 0){
    printf("server thread trys to read from socket...\n");
        //read-part
    while(1){
                bzero(sar->buffer, 256);
                n = read(sar->newsockfd, sar->buffer, 255);
                if (n < 0){
                        error("ERROR reading from socket");
                      }
        }
                printf("%s\n", sar->buffer);
    } else {
    printf("server thread trys to write to socket...\n");
    //write-part
    while(1){
                bzero(sar->buffer, 256);
                fgets(sar->buffer, 255, stdin);
                n = write(sar->newsockfd, sar->buffer, strlen((char *) &(sar->buffer)));
                if (n < 0){
                        error("ERROR writing to socket");
                }

    }
    }
}


int main(int argc, char *argv[]){
    //fd = filedescriptor
    int sockfd, portno, clilen;
    struct sockaddr_in serv_addr, cli_addr;
    int n;

    if (argc < 2){
        fprintf(stderr,"ERROR, no port provided\n");
        exit(1);
    }
    //socket(...) returns a descriptor
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd == -1){
        error("ERROR opening socket");
    }
    printf("Socket created successfully.\n");
    bzero((char *) &serv_addr, sizeof(serv_addr));

    portno = atoi(argv[1]);

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    //htons(..) converts the short from hostbyteorder to networkbyteorder
    serv_addr.sin_port = htons(portno);

    if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) == -1){
        error("ERROR on binding");
    }
    printf("binding successfull on port %d\n", portno);

    listen(sockfd, 2);
    clilen = sizeof(cli_addr);
    printf("server is listening ...\n");

    struct server_args_runner server_write_t, server_read_t;
    server_write_t.newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);
    printf("server accepted connection to client.\n");
    if (server_write_t.newsockfd < 0){
        error("ERROR on accept");
    }

    //initializing both server_threads
    pthread_attr_init(&server_write_t.attr);
    pthread_attr_init(&server_read_t.attr);
    server_write_t.rw = 1;
    server_read_t.rw = 0;
    bcopy(&server_write_t.newsockfd, &server_read_t.newsockfd, sizeof(server_write_t.newsockfd));
    pthread_create(&server_write_t.tid, &server_write_t.attr, server_runner_fun, &server_write_t);
    pthread_create(&server_read_t.tid, &server_read_t.attr, server_runner_fun, &server_read_t);

    pthread_join(server_write_t.tid, NULL);
    pthread_join(server_read_t.tid, NULL);

    return 0;
}

Client code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>

struct client_args_runner{
        char buffer [256];
        int sockfd;
        pthread_t tid;
        pthread_attr_t attr;
        //read/write attribute (read == 0 and write == 1)
        int rw;
};


void error(char *msg){
    perror(msg);
    exit(0);
}

void* client_runner_fun(void* args){
        // this is the chat part!
        // get args:
        int n;
        struct client_args_runner *car = (struct client_args_runner*) args;
        if(car->rw == 0){
        printf("client thread trys to read from socket...\n");
    //read-part
        while(1){
                bzero(car->buffer, 256);
                n = read(car->sockfd, car->buffer, 255);
                if (n < 0){
                        error("ERROR reading from socket");
                          }
                }
                printf("%s\n", car->buffer);
        } else {
    printf("client thread trys to write to socket...\n");
        //write-part
        while(1){
                bzero(car->buffer, 256);
                fgets(car->buffer, 255, stdin);
                n = write(car->sockfd, car->buffer, strlen((char *) &(car->buffer)));
                if (n < 0){
                        error("ERROR writing to socket");
                }

        }
        }
}


int main(int argc, char *argv[]){

    int portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    if (argc < 3){
        fprintf(stderr,"usage %s hostname port\n", argv[0]);
        exit(0);
    }

    portno = atoi(argv[2]);

    struct client_args_runner client_write_t, client_read_t;

    client_write_t.sockfd = socket(AF_INET, SOCK_STREAM, 0);
    bcopy(&client_write_t.sockfd, &client_read_t.sockfd,
                    sizeof(client_write_t.sockfd));
    if (client_write_t.sockfd == -1){
        error("ERROR on creating socket_file_descriptor");
    }
    printf("socket created successfully.\n");
    server = gethostbyname(argv[1]);
    printf("hostname is valid.\n");
    if(server == NULL){
        fprintf(stderr, "Error, no such host\n");
        exit(0);
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;

        bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
    serv_addr.sin_port = htons(portno);
    printf("before connecting to client..\n");
    if (connect(client_write_t.sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) == -1){
        error("ERROR connecting");
    }
    printf("client connected successfully to server.\n");

    //initializing both client_threads
        pthread_attr_init(&client_write_t.attr);
        pthread_attr_init(&client_read_t.attr);
        client_write_t.rw = 1;
        client_read_t.rw = 0;
    pthread_create(&client_write_t.tid, &client_write_t.attr, client_runner_fun, &client_write_t);
        pthread_create(&client_read_t.tid, &client_read_t.attr, client_runner_fun, &client_read_t);

        pthread_join(client_write_t.tid, NULL);
        pthread_join(client_read_t.tid, NULL);

        return 0;

}

Solution

  • Your printfs in both the client and server readers are outside the while(1) loops, so your client and server are communicating fine, you just aren't printing anything you read from the sockets.