Linir
Linir

Reputation: 388

Running client and server socket connection in C - With threads

I am trying to create a simple socket connection of a client and a server. I wrote something very basic, following this guide.

I am using the client.c:

#include <stdio.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <unistd.h> 
#include <string.h> 
#define PORT 8080 
   
int client() 
{ 
    int sock = 0, valread; 
    struct sockaddr_in serv_addr; 
    char *hello = "Hello from client"; 
    char buffer[1024] = {0}; 
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
    { 
        printf("\n Socket creation error \n"); 
        return -1; 
    } 
   
    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_port = htons(PORT); 
       
    // Convert IPv4 and IPv6 addresses from text to binary form 
    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)  
    { 
        printf("\nInvalid address/ Address not supported \n"); 
        return -1; 
    } 
   
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) 
    { 
        printf("\nConnection Failed \n"); 
        return -1; 
    } 
    send(sock , hello , strlen(hello) , 0 ); 
    printf("Hello message sent\n"); 
    valread = read( sock , buffer, 1024); 
    printf("%s\n",buffer ); 
    return 0; 
} 

and the server.c:

#include <unistd.h> 
#include <stdio.h> 
#include <sys/socket.h> 
#include <stdlib.h> 
#include <netinet/in.h> 
#include <string.h> 
#define PORT 8080 

int server() 
{ 
    int server_fd, new_socket, valread; 
    struct sockaddr_in address; 
    int opt = 1; 
    int addrlen = sizeof(address); 
    char buffer[1024] = {0}; 
    char *hello = "Hello from server"; 
       
    // Creating socket file descriptor 
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) 
    { 
        perror("socket failed"); 
        exit(EXIT_FAILURE); 
    } 
       
    // Forcefully attaching socket to the port 8080 
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, 
                                                  &opt, sizeof(opt))) 
    { 
        perror("setsockopt"); 
        exit(EXIT_FAILURE); 
    } 
    address.sin_family = AF_INET; 
    address.sin_addr.s_addr = INADDR_ANY; 
    address.sin_port = htons( PORT ); 
       
    // Forcefully attaching socket to the port 8080 
    if (bind(server_fd, (struct sockaddr *)&address,  
                                 sizeof(address))<0) 
    { 
        perror("bind failed"); 
        exit(EXIT_FAILURE); 
    } 
    if (listen(server_fd, 3) < 0) 
    { 
        perror("listen"); 
        exit(EXIT_FAILURE); 
    } 
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address,  
                       (socklen_t*)&addrlen))<0) 
    { 
        perror("accept"); 
        exit(EXIT_FAILURE); 
    } 
    valread = read( new_socket , buffer, 1024); 
    printf("%s\n",buffer ); 
    send(new_socket , hello , strlen(hello) , 0 ); 
    printf("Hello message sent\n"); 
    return 0; 
} 

One important change that I want to make is running the client and the server from a single code file, where I use pthread to run the server on a single thread while running the client on another thread.

I was working with pthreads before, however this time it doesn't work properly. No message is being sent and it looks like the server is not listening. Here is what the main function looks like:

int main(){
pthread_t threads[NUM_THREADS];
int ret;
printf("In main: creating thread server\n");
ret = pthread_create(&threads[0], NULL, &server, NULL);
if (ret){
    printf("ERROR; return code from pthread_create() is %d\n", ret);
    exit(-1);
}

printf("In main: creating thread client\n");
ret = pthread_create(&threads[1], NULL, &client, NULL);
if (ret){
    printf("ERROR; return code from pthread_create() is %d\n", ret);
    exit(-1);
}
}

Where the client and server functions are basic function, exactly the same one from the guide mentioned before. The threads are created and the main function executes without errors, but the server and client functions do not run properly. I started suspecting maybe socket connection cannot run in a thread-like configuration. Would appreciate any help in that matter.

edit: After checking the server file execution, I noticed it get lost inside the accept function. To be more specific, in the server.c file:

    if ((new_socket = accept(server_fd, (struct sockaddr *)&address,  
                       (socklen_t*)&addrlen))<0) 
    { 
        perror("accept"); 
        exit(EXIT_FAILURE); 
    } 

It doesn't go past this function, meaning that it does hit the 'accept' function, and it goes inside of it, but it never leaves it. It never assign any value to new_socket nor does it go inside the if statement to hit the perror("accept");

Thank you

Upvotes: 2

Views: 848

Answers (1)

snus74
snus74

Reputation: 461

From the info you gave in the comments, linked with @Andreas Wenzel, @encs and @IS comments:

  • You need to wait for the threads to finish. add a join function to block the main thread meanwhile the other threads are running
  • use fflush() after every printf() to avoid issues related to buffering
  • The server should be in Listen state before any client tries to connect. To ensure that, setup the server in the main thread, and create a pthread for everything below the accept() function.

Upvotes: 4

Related Questions