Running client and server socket connection in C - With threads - c

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

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.

Related

socket binding failed (address already in use, even with SO_REUSEADDR)

I am working in a simple socket project. I would like to know:
why error messages appear before telnet localhost 5678?
why SO_REUSEADDR (between socket() and bind()) don't work, and what else I should try?
Code Output Message:
bind error
Error opening file: Address already in use
telnet localhost 5678
[+]Server Socket is created.
main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#define BUFSIZE 1024 // Buffer Size
#define PORT 5678
int main() {
printf("telnet localhost 5678\n");
int rfd; // socket descriptor
int clientfd; // client descriptor
struct sockaddr_in client; // Client Socket address
socklen_t client_len; // Length of Client Data
char input[BUFSIZE]; // Client Data -> Server
int bytes_read; // Client Bytes
// 1. socket() = create a socket, SOCK_STREAM = TCP
rfd = socket(AF_INET, SOCK_STREAM, 0);
if (rfd < 0) {
fprintf(stderr, "socket error\n");
exit(-1);
}
printf("[+]Server Socket is created.\n");
// optional
int enable = 1;
if (setsockopt(rfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
fprintf(stderr, "setsockopt(SO_REUSEADDR) failed");
//Initialize the server address by the port and IP
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET; // Internet address family: v4 address
server.sin_addr.s_addr = INADDR_ANY; // Server IP address
server.sin_port = htons(PORT); // Server port
// 2. bind() = bind the socket to an address
int brt = bind(rfd, (struct sockaddr *) &server, sizeof(server));
if (brt < 0) {
int errnum;
errnum = errno;
fprintf(stderr, "bind error\n");
fprintf(stderr, "Error opening file: %s\n", strerror(errnum));
exit(-1);
}
printf("[+]Bind to port %d\n", PORT);
// 3. listen() = listen for connections
int lrt = listen(rfd, 50);
if (lrt < 0) {
printf("listen error\n");
exit(-1);
}
if (lrt == 0) {
printf("[+]Listening....\n");
}
// non-stop loop
while (1) {
// 4. accept() = accept a new connection on socket from client
clientfd = accept(rfd, (struct sockaddr *) &client, &client_len);
if (clientfd < 0) {
fprintf(stderr, "accept failed with error %d\n");
exit(-1);
}
printf("Client connected\n");
...
close(clientfd);
printf("Client disconnected\n");
}
close(rfd);
}
I'm assuming that you are using Linux. If you want to rebind to an address, you should use SO_REUSEPORT not SO_REUSEADDR. Name is really misleading. But make sure that you know how it works and whether you really want to use it or not.
You can check difference here: How do SO_REUSEADDR and SO_REUSEPORT differ?

raspberry pi websocket client program hangs when connected to raspberry pi access point

I have a simple websocket program where a server and client exchange a message and then exit, taken from a geeks for geeks tutorial:
https://www.geeksforgeeks.org/socket-programming-cc/
server.c:
// Server side C/C++ program to demonstrate Socket programming
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
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;
}
client.c:
// Client side C/C++ program to demonstrate Socket programming
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
printf("$");
int sock = 0, valread;
struct sockaddr_in serv_addr;
char *hello = "Hello from client";
char buffer[1024] = {0};
printf("#");
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
printf("#");
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary form
//CURRENT IP IS RPI4 IP
if(inet_pton(AF_INET, "192.168.0.12", &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;
}
printf("!\n");
send(sock , hello , strlen(hello) , 0 );
printf("Hello message sent\n");
valread = read( sock , buffer, 1024);
printf("%s\n",buffer );
return 0;
}
My raspberry pi 4 is the server and my raspberry pi 3 is the client. On my normal home wifi network this program executes exactly as expected.
However I have turned my RPI4 into a standalone wifi access point using this tutorial: https://www.raspberrypi.org/documentation/configuration/wireless/access-point-routed.md
When I connect the RPI3 client to the RPI4 network, and run the server and then the client program it hangs and seems like it isn't even running the first line of code and printing the "$", (this may not be the case as the assembler may move the first print statement somewhere else in execution).
I'm assuming this isn't a problem with my either of my programs but a problem with either the RPI4 access point or the RPI3's connection to the access point, but I know very little about networking. Can someone help me troubleshoot and pinpoint what the problem is?

Attempting to create a basic socket connection in C and running into an infinite loop on accept()

I have an assignment where I need to create a simple HTTP server to handle GET requests and return info from a directory in the directory holding the executable for this code. I am trying to establish a connection between the sockets before ironing out the HTTP requests. However, when I try to connect the client to the server using accept() it triggers an infinite loop with gdb displaying this message:
../sysdeps/unix/sysv/linux/accept.c:26
26 ../sysdeps/unix/sysv/linux/accept.c: No such file or directory.
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
int main(int argc, char* argv[]){
if(argc>1){
perror("Error there should be no command line arguments");
exit(0);
}
int sockfd = 0;
int clientfd = 0;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0))<0){ //create socket and check for error
perror("Error in socket creation");
exit(0);
}
//create sockaddr object to hold info about the socket
struct sockaddr_in server, client;
server.sin_family = AF_INET;
server.sin_port = 0;
server.sin_addr.s_addr = htonl(INADDR_ANY);
socklen_t sockSize = sizeof(server);
//Bind the socket to a physical address exit if there is an error
if((bind(sockfd, (struct sockaddr*)&server, sockSize))<0){
perror("Error binding socket");
exit(0);
}
//Check server details
printf("-------Server Details----------\n");
printf("Port number %d | IP ADDRESS %d\n", ntohs(server.sin_port), (getsockname(sockfd, (struct sockaddr*)&server, &sockSize)));
if((getsockname(sockfd, (struct sockaddr*)&server, &sockSize)) <0){
perror("There is an error in the sock");
exit(0);
}
if(listen(sockfd, 5) <0){
perror("Error switching socket to listen");
exit(0);
}
while((clientfd = accept(sockfd, (struct sockaddr*)&client, (socklen_t*)&sockSize))){
printf("Socket is awaiting connections");
}
// figure out how to setup client to accept and submit HTTP requests
close(sockfd);
return 0;
}
accept() returns -1 on failure. An if will treat any non-zero value as a true condition.
Your loop should look more like the following:
// setup listening socket...
printf("Socket is awaiting connections");
while (1) {
sockSize = sizeof(client); // <-- add this
if ((clientfd = accept(sockfd, (struct sockaddr*)&client, (socklen_t*)&sockSize)) < 0) {
if (errno != EINTR) {
// fatal error, bail out...
break;
}
continue; // retry...
}
printf("Client connected");
// use clientfd to read HTTP request and send HTTP response...
close(clientfd);
}

Simple HTTP Server C code doesn't work on my Mac OS X

I am trying to implement a very simple HTTP server C code, and while doing that I search this on the web :
https://medium.com/from-the-scratch/http-server-what-do-you-need-to-know-to-build-a-simple-http-server-from-scratch-d1ef8945e4fa
And I copy-and-paste the code which is shown below.(also the code in the link up there)
And I build it and run it on my MacBook,
and it runs on my computer, so I typed "localhost:8080" on Safari.
And I have this result only.
Safari Can't Connect to the Server
Safari can't open the page "localhost:8080" because Safari can't connect to the server "localhost".
I have no idea why this is not working. According to that site, It should work, so I am now frustrated.
Anyone please help me?
// Server side C program to demonstrate HTTP Server programming
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
int server_fd, new_socket; long valread;
struct sockaddr_in address;
int addrlen = sizeof(address);
// Only this line has been changed. Everything is same.
char *hello = "HTTP/1.1 200 OK\nContent-Type: text/plain\nContent-Length: 12\n\nHello world!";
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("In socket");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
memset(address.sin_zero, '\0', sizeof address.sin_zero);
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("In bind");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 10) < 0)
{
perror("In listen");
exit(EXIT_FAILURE);
}
while(1)
{
printf("\n+++++++ Waiting for new connection ++++++++\n\n");
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("In accept");
exit(EXIT_FAILURE);
}
char buffer[30000] = {0};
valread = read( new_socket , buffer, 30000);
printf("%s\n",buffer );
write(new_socket , hello , strlen(hello));
printf("------------------Hello message sent-------------------");
close(new_socket);
}
return 0;
}

multithread server/client implementation in C

I have just started learning basic networking concepts.I am trying to implement a multithread server-client prog in C.but the problem is instead of running multiple windows/terminals/instances for clients,i should use fork() to create children of client.so by creating children of client multiple clients will be created.now each of these child clients will communicate with the server on a thread.
Earlier i created a similar prog but in that for multiple client you have to open multiple windows for clients and run all of them.
I am having trouble where to modify my code (both in server and client ones.I think server one is ok.but i am having no idea where to fork() in client program and what changes should be made).
Actually i don't want to open multiple windows to run multiple client,thats why i am using fork() to create multiple copies of it.Is there any other way by which i can create multiple clients and connect them to my server prog via threads.
Server :
// socket server example, handles multiple clients using threads
#include<stdio.h>
#include<string.h> //strlen
#include<stdlib.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write
#include<pthread.h> //for threading , link with lpthread
//the thread function
void *connection_handler(void *);
int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , *new_sock;
struct sockaddr_in server , client;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 3000 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
c=sizeof(struct sockaddr_in);
while(client_sock=accept(socket_desc,(struct sockaddr*)&client,(socklen_t*)&c))
{
puts("Connection accepted");
pthread_t sniffer_thread;
new_sock = malloc(1);
*new_sock = client_sock;
if( pthread_create( &sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0)
{
perror("could not create thread");
return 1;
}
puts("Handler assigned");
}
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
return 0;
}
/*
This will handle connection for each client
*/
void *connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;
int n;
char sendBuff[100], client_message[2000];
while((n=recv(sock,client_message,2000,0))>0)
{
send(sock,client_message,n,0);
}
close(sock);
if(n==0)
{
puts("Client Disconnected");
}
else
{
perror("recv failed");
}
return 0;
}
Client:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_SIZE 50
int main()
{
int sock_desc;
struct sockaddr_in serv_addr;
char sbuff[MAX_SIZE],rbuff[MAX_SIZE];
if((sock_desc = socket(AF_INET, SOCK_STREAM, 0)) < 0)
printf("Failed creating socket\n");
bzero((char *) &serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(3000);
if (connect(sock_desc, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
printf("Failed to connect to server\n");
return -1;
}
printf("Connected successfully - Please enter string\n");
while(fgets(sbuff, MAX_SIZE , stdin)!=NULL)
{
send(sock_desc,sbuff,strlen(sbuff),0);
if(recv(sock_desc,rbuff,MAX_SIZE,0)==0)
printf("Error");
else
fputs(rbuff,stdout);
bzero(rbuff,MAX_SIZE);//to clean buffer-->IMP otherwise previous word characters also came
}
close(sock_desc);
return 0;
}
You can create multiple clients using thread. Create a separate thread for each client and then from thread handler connect to the server. I am not sure if it is a good way or not.
Code:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_SIZE 50
#define NUM_CLIENT 5
void *connection_handler(void *socket_desc);
int main()
{
int socket_desc , new_socket , c , *new_sock, i;
pthread_t sniffer_thread;
for (i=1; i<=NUM_CLIENT; i++) {
if( pthread_create( &sniffer_thread , NULL , connection_handler , (void*) i) < 0)
{
perror("could not create thread");
return 1;
}
sleep(3);
}
pthread_exit(NULL);
return 0;
}
void *connection_handler(void *threadid)
{
int threadnum = (int)threadid;
int sock_desc;
struct sockaddr_in serv_addr;
char sbuff[MAX_SIZE],rbuff[MAX_SIZE];
if((sock_desc = socket(AF_INET, SOCK_STREAM, 0)) < 0)
printf("Failed creating socket\n");
bzero((char *) &serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(8888);
if (connect(sock_desc, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
printf("Failed to connect to server\n");
}
printf("Connected successfully client:%d\n", threadnum);
while(1)
{
printf("For thread : %d\n", threadnum);
fgets(sbuff, MAX_SIZE , stdin);
send(sock_desc,sbuff,strlen(sbuff),0);
if(recv(sock_desc,rbuff,MAX_SIZE,0)==0)
printf("Error");
else
fputs(rbuff,stdout);
bzero(rbuff,MAX_SIZE);
sleep(2);
}
close(sock_desc);
return 0;
}
For understanding purpose, i used sleep.
REF:
http://www.amazon.com/UNIX-Network-Programming-Richard-Stevens/dp/0139498761
http://beej.us/guide/bgnet/
https://computing.llnl.gov/tutorials/pthreads/
Firstly, if you fork(), you will be creating additional processes, not additional threads. To create additional threads, you want to use pthread_create.
Secondly, as you are a student, the canonical answer here is 'read Stephens'. Not only is this an invaluable tool even for those of us experienced in writing socket I/O routines, but also it contains examples of non-threaded non-forking async I/O, and various ways to add threads and forking to them. I believe the one you want is: http://www.amazon.com/Programming-Environment-Addison-Wesley-Professional-Computing/dp/0321637739 (chapter 14 if memory serves). This should be in your college library.

Resources