2

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

Linir
  • 361
  • 1
  • 2
  • 10
  • 2
    I believe we'd need to see a [mcve] of the problem. Also, a better description of the problem behavior would likely help as well. – Carcigenicate Aug 19 '20 at 13:47
  • 1
    If this isn't a toy/study project, I would recommend using a library for that. The problem was solved multiple times with varying degrees of successful API design... one point I would make is that a thread-per-connection design is resource intensive and should probably be limited to servers that serve a small amount of clients. – Myst Aug 19 '20 at 13:52
  • 1
    could you share the code of the server and client please. Have you checked if your threads are running? This is done easily by putting a printf() in each thread. I am pretty sure running a client and server on the same process on different threads is possible. – snus74 Aug 19 '20 at 13:55
  • @snus74 Thank you, I didn't want to write too much code on the question page, this is why I added the website where I used exactly the same client and server code from there. – Linir Aug 19 '20 at 13:56
  • 1
    @Linir Ok. please proceed with the checks that your threads run. – snus74 Aug 19 '20 at 13:57
  • 1
    @Carcigenicate the link to the missing code is present. He is spawning two threads from the main thread. So he is NOT running the client from the server thread. This is pretty straightforward to see from his code example. You are not being very helpful... – snus74 Aug 19 '20 at 13:59
  • Except that all code must be posted here in case the link goes down. Attempting to get his question within site rules so it isn't closed in indeed helpful, but you're free to believe what you like. – Carcigenicate Aug 19 '20 at 14:00
  • 1
    @Carcigenicate ok for the compliance of the question to the site rules. Still your comment about running the client from the server thread showed careless reading of the question. – snus74 Aug 19 '20 at 14:03
  • @snus74 Thank you for your helpful comments, I edited the main question. – Linir Aug 19 '20 at 14:04
  • 1
    @Linir what do you mean by stuck? does it exit the program or does it stall ( accept is a blocking call that waits until a client tries connecting – snus74 Aug 19 '20 at 14:09
  • @snus74 Sorry if my wording is a bit unclear, I will rephrase it also in the main question. I meant that it goes into the 'accept' function, however it never goes out of it. It never hits the ```perror("accept");```. I am not sure as to how to debug it inside the 'accept' function. – Linir Aug 19 '20 at 14:12
  • 1
    @Linir its fine. The behavior you get probably means that your server is running OK, but it doesnt receive the connection request from your client. Did you try putting printfs() in the client code to see if it actually runs the connect() function? – snus74 Aug 19 '20 at 14:14
  • @snus74 Feeling really stupid right now.. It actually never runs the client code. I checked the name of everything and it should run, but maybe I did something wrong in the initiating of the thread? Edit: When I swapped the order of the thread_create, it does run the client. Meaning it only runs the first thread – Linir Aug 19 '20 at 14:17
  • 2
    Note that when using `printf` for debugging purposes, it is important to make sure that the buffer gets flushed (for example by calling the function `fflush`) immediately afterwards. See [this question](https://stackoverflow.com/q/1716296/12149471) for further information. – Andreas Wenzel Aug 19 '20 at 14:18
  • 2
    Maybe you should put some delay before running client thread. Make sure server ready to accept connections before client trying to connect. – I S Aug 19 '20 at 14:22
  • 1
    @Linir I suggest you comment out the thread creation for the server and see if your client runs on its own. It should exit the program with " printf("\nConnection Failed \n"); " – snus74 Aug 19 '20 at 14:22
  • 1
    @IS True, but the output should be a connection error rather than the client not running at all – snus74 Aug 19 '20 at 14:24
  • @snus74 Thank you, I did comment out the server and ran only the client. It does run and returns connection failed. – Linir Aug 19 '20 at 14:26
  • 2
    problem is very likely in the (not provided) `main()` function. I suspect something like returning immediately instead of waiting for the threads to finish. Issues like bad thread function prototypes or the `exit()` within the thread functions should be negligible for this issue. – ensc Aug 19 '20 at 14:31
  • Thanks @ensc, the main() function is exactly what I have in the main question. nothing more, nothing less. Should I change something with it? – Linir Aug 19 '20 at 14:32
  • 1
    @Linir you have to wait for the threads to finish or -- for testing -- add something like a `sleep(100)`. – ensc Aug 19 '20 at 14:33

1 Answers1

4

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.
snus74
  • 384
  • 2
  • 8
  • Thank you! it helped! It is now working. The problem was as you said, setting the Listen before the client tries to connect. So I had to create the server thread after the initialization. – Linir Aug 19 '20 at 15:40