0

I'm trying to implement a multithreaded C server-client as implemented here

I want to work with an infinite loop to read/send messages as much as I want, until let's say the client sends SIGINT or SIGSTOP signal or writes the message "stop". So far only the first message that the client sends is received by the server, and for this the server responds with "abcd" as shown in code. Starting with the 2nd message, I can't see the server replies in the client anymore, and like from the 3rd message, the client just exits, like the connection is ended. Meanwhile, the server is still running. I will put my code below, I don't think I am working correctly with write/read.

server.c

#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 <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/syscall.h> //thread_id

#define PORT 7507
#define BUFFER_SIZE 2048
#define BACKLOG 10
#define gettid() ((pid_t)syscall(SYS_gettid))

typedef struct pthread_args {
    int sockfd;
    struct sockaddr_in client_address;
    
    clock_t start, stop; 
    
    char* message;
    float seconds;
    float delay; 
} pthread_args;

void* handler(void* args) {
    pthread_args* pthread_arg = (pthread_args*)args;
    int sockfd = pthread_arg->sockfd;
    struct sockaddr_in client_address = pthread_arg->client_address;
    float seconds = pthread_arg->seconds;
    float delay = pthread_arg->delay;
    char* message = pthread_arg->message;   
    
    free(args);
    
    printf("Message received from client (thread id=%d): %s\n", gettid(), pthread_arg->message);
    
    if((write(sockfd, "abcd", 4))<0) {
        perror("write");
        exit(EXIT_FAILURE);
    }
    
    close(sockfd);
    return NULL;    
}

int main() {
    int sockfd, new_sockfd, bytes;
    char buffer[BUFFER_SIZE];
    struct sockaddr_in server_address;
    
    pthread_attr_t pthread_attr;
    pthread_args* pthread_arg;
    pthread_t thread;
    
    socklen_t client_len;
    
    memset(&server_address, 0, sizeof(server_address));
        server_address.sin_family = AF_INET;
        server_address.sin_port = htons(PORT);
        server_address.sin_addr.s_addr = INADDR_ANY;
        
        //socket
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            perror("socket");
            exit(EXIT_FAILURE);
        }
        
        //bind
        if (bind(sockfd, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) {
            perror("bind");
            exit(EXIT_FAILURE);
    }
    
    //listen
    if (listen(sockfd, BACKLOG) == -1) {
            perror("listen");
            exit(EXIT_FAILURE);
        }
        
        if (pthread_attr_init(&pthread_attr) != 0) {
            perror("pthread_attr_init");
            exit(EXIT_FAILURE);
        }
        
    if (pthread_attr_setdetachstate(&pthread_attr, PTHREAD_CREATE_DETACHED) != 0) {
            perror("pthread_attr_setdetachstate");
            exit(EXIT_FAILURE);
        }
        
        while(1) {
            pthread_arg = (pthread_args*)malloc(1*sizeof(pthread_args*));
            
            if(!pthread_arg) {
                perror("malloc");
                exit(EXIT_FAILURE);
            }
            
            //accept
            client_len = sizeof(pthread_arg->client_address);
            new_sockfd = accept(sockfd, (struct sockaddr*)&pthread_arg->client_address, &client_len);
            if(new_sockfd == -1) {
                perror("accept");
                free(pthread_arg);
                exit(EXIT_FAILURE);
            }
            
            bzero(buffer, BUFFER_SIZE-1);
            if((read(new_sockfd, &buffer, BUFFER_SIZE-1))<0) {
                perror("read");
                exit(EXIT_FAILURE);
            }
            
            pthread_arg->sockfd = new_sockfd;
            pthread_arg->message=(char*)malloc(strlen(buffer));
            if(!pthread_arg->message) {
                perror("malloc");
                exit(EXIT_FAILURE);
            }
            strcpy(pthread_arg->message, buffer);
            pthread_arg->seconds = 0;
            pthread_arg->delay = 0;
            
            if(pthread_create(&thread, &pthread_attr, handler, (void*)pthread_arg) != 0) {
                perror("pthread_create");
                free(pthread_arg);
                exit(EXIT_FAILURE);
            }
        }
    
    shutdown(sockfd, SHUT_RDWR);
    close(sockfd);
    return 0;

}

client.c

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

#define PORT 7507
#define SERVER "localhost"
#define BUFFER_SIZE 2048

int main(int argc, char *argv[])
{
    int sockfd, bytes;
    
    struct hostent* server_host;
    struct sockaddr_in server_address;
    
    char message_sent[BUFFER_SIZE];
    char message_received[BUFFER_SIZE];
    
    if(argc>1) {
        printf("too many arguments\n");
        exit(EXIT_FAILURE);
    }
    
    server_host = gethostbyname(SERVER);
    
    memset(&server_address, 0, sizeof(server_address));
        server_address.sin_family = AF_INET;
        server_address.sin_port = htons(PORT);
        memcpy(&server_address.sin_addr.s_addr, server_host->h_addr, server_host->h_length);
        
        //socket
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            perror("socket");
            exit(EXIT_FAILURE);
        }
        
        //connect
        if (connect(sockfd, (struct sockaddr *)&server_address, sizeof server_address) == -1) {
        perror("connect");
            exit(EXIT_FAILURE);
    }
    
    while(1) {
        bzero(message_sent, sizeof(message_sent));
        printf("Your message: ");
        fgets(message_sent, BUFFER_SIZE-1, stdin);
        message_sent[strcspn(message_sent, "\n")]=0;
        
        //sending to server
        if((write(sockfd, &message_sent, strlen(message_sent)))<0) {
            perror("write");
            exit(EXIT_FAILURE);
        }
    
        bzero(message_received, sizeof(message_received));
        //reading from server
        if ((read(sockfd, &message_received, BUFFER_SIZE-1))<0)
        {
            perror("read");
            exit(EXIT_FAILURE);
        }
    
        printf("Server says: %s\n", message_received);
    }
    
    close(sockfd);
    return 0;
}

OUTPUT in terminal:

For client:

Your message: message1

Server says: abcd

Your message: message2

Server says:

Your message: message3

Server says:

client automatically stops

For server:

Message received from client (thread id=x): message1

and here it stops, I dont see message2 and message3 received but the server is still running

Bodvub
  • 43
  • 4
  • 1
    The server handler thread sends _one_ message (e.g. `abcd`) and then _terminates_ [closing the connection]. But, the client receives the message and loops. The second time it is waiting/reading on a connection that has been closed by the server. The server function should loop. The server sends the message immediately. I'd rearchitect things. Client must send a message first. Server receives message and sends response. Client reads response. Client loops and sends another message. Each side loops on this. When client has all it needs, it sends "stop". server thread sees this and terminates – Craig Estey Nov 18 '22 at 18:32
  • 1
    Here's a client/server answer of mine: [thread function doesn't terminate until Enter is pressed](https://stackoverflow.com/a/72341219/5382650) that may help. – Craig Estey Nov 18 '22 at 18:40
  • @CraigEstey so I need to loop in the handler thread function like I do with the client, until let's say the message sent by the client is stop (in which case I close the socket)? – Bodvub Nov 19 '22 at 08:05

0 Answers0