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.
Related
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.
I want to make a server-client programm.The first thing i can't find is to make the server never shut down and accept each client.I put a while(1) on my server to run but after 3 connections to one client my server stops accepting other connections and i delete this while.I cant find how to build this think.Also i want to create TCP/IP socket so am i making the socket with the right way?
Im working on ubuntu at Visual Studio Code.
Server:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#define PORT 8080
int main(int argc,char* argv[]){
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char *hello = "Hello from server";
while(1){
char buffer[1024] = {0};
printf("Server\n");
// 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, 1) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("Listening...\n");
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;
}
My client so far:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#define PORT 8080
int main(int argc,char* argv[]){
char* command = (char*) malloc(15*sizeof(char));
int sock = 0, valread;
struct sockaddr_in serv_addr;
char *hello = "Hello from client";
char buffer[1024] = {0};
printf("Client\n");
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;
}
You have to put the loop only around the code, which accepts the clients. The server socket itself is only created once.
// Creation of server socket(), bind(), listen()
while (1) {
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");
}
Furthermore, you should close the client socket at the end of the while block after the communication is finished (i.e. after the printf("Hello message sent\n");:
close(new_socket);
And note, that the clients are served serially this way. They can connect concurrently, but only one client is served at a time. If you need concurrent handling, you can for example fork() several processes, each handling one client, or handle multiple clients in one thread using poll() or select().
I am writing a TCP client in C.
Following several tutorial I wrote my code but it can accept only the first connection to the server.
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h> //inet_addr for INADDR_ANY
#include <string.h> //for splitting (strtok)
#include <pthread.h> //thread library
#include <time.h>
#include <unistd.h> //for function close()
void* SocketHandler(void*);
int main(void) {
//socket parameters
int server_socket_desc;
int clientAddressLength = sizeof(struct sockaddr_in);
struct sockaddr_in server_addr, client_addr;
const unsigned short int PORT_NUMBER = 8963;
server_socket_desc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_socket_desc < -1) {
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server_addr.sin_family = AF_INET; //it should be always set to AF_INET
//set the server address
server_addr.sin_addr.s_addr = inet_addr("192.168.123.240");
//server_addr.sin_addr.s_addr = inet_addr("31.185.101.35");
//server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(PORT_NUMBER);
//Bind
if (bind(server_socket_desc, (struct sockaddr *) &server_addr,
sizeof(server_addr)) < 0) {
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(server_socket_desc, 10);
//Accept and incoming connection
puts("Waiting for incoming connections...");
//accept connection from an incoming client
while (1) {
int *temp_socket_desc = (int*) malloc(sizeof(int));
if ((*temp_socket_desc = accept(server_socket_desc,
(struct sockaddr *) &client_addr,
(socklen_t*) &clientAddressLength)) != -1) {
printf("----------\nConnection accepted \n");
sleep(1);
pthread_t thread_id;
int *client_socket_desc = (int*) malloc(sizeof(int));
client_socket_desc = temp_socket_desc;
pthread_create(&thread_id, NULL, &SocketHandler,
(void*) client_socket_desc);
//if thread has not terminated, pthread_detach() shall not cause it to terminate
pthread_detach(thread_id);
puts("handler assigned");
} else
puts("connection refused");
}
close(server_socket_desc);
//mysql_close(mysql_conn);
return 0;
}
/*
* This will handle connection for each client
* */
void* SocketHandler(void* lp) {
int *csock = (int*) lp;
char buffer[128];
int buffer_len = 128;
int bytecount;
memset(buffer, 0, buffer_len);
if ((bytecount = read(*csock, buffer, buffer_len) == -1)) {
fprintf(stderr, "Error receiving data\n");
close(*csock);
return 0;
}
printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
close(*csock);
free(csock);
puts("exiting thread");
//pthread_exit(0);
return 0;
}
I temporally solved the problem inserting a sleep() after the while loop but it is a very bad solution.
Can somebody explain me why the code does'n work without the sleep?
There is a problem in handling of client_socket_desc:
You allocate it only once. All threads will get the same pointer.
So later accepts will override socket descriptors value of earlier threads.
Try the following change, for allocating own memory block for each thread:
int fd = accept( server_socket_desc, (struct sockaddr *) &client_addr, (socklen_t*)
&clientAddressLength)
if ( fd != -1 )
{
pthread_t thread_id;
int *client_socket_desc = malloc(sizeof(int));
*client_socket_desc = fd;
pthread_create(&thread_id, NULL, &SocketHandler,(void*) client_socket_desc);
...
Or course you must add error handlings for malloc and pthread_create.
And also free the allocated memory when not needed anymore.
I don't understood why there is the following code in the while loop:
if(send(*client_socket_desc,buffer,1,MSG_NOSIGNAL)>0)
{
puts("closing client socket");
close(*client_socket_desc);
}
Close client sockets in client handler threads.
I have written a code for client server model. It works fine if I pass value in program but when I tried to do it by passing address.
I am making quite a few silly mistakes which i am not able to figure out. I have also tried to make 100 threads using pthreads concept,basic intention was that when a client side pings my server and sends message server echoes it back and it can assign any one of the 100 threads message that client has sent. but how to do this... i am still working on that.
Here is my code for server:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/uio.h>
#define NTHREADS 100
void *connection_handler(void *);
pthread_t thread_id[NTHREADS];
pthread_mutex_t lock;
int service_count, sockfd,d1;
struct sockaddr_in server , client;
// Socket create
int sock_create( )
{
sockfd= socket(AF_INET , SOCK_STREAM , 0);
if (sockfd <0)
{
printf("Could not create socket");
return 1;
}
puts("Socket created");
memset(&server,0,sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 2100);
}
// Bind
int sock_bind()
{
int b= bind(sockfd,(struct sockaddr *)&server , sizeof(server));
if (b <0)
{
perror("Bind failed. Error");
return 1;
}
puts("Bind");
}
// Listen
int sock_listen()
{
listen(sockfd , 10);
}
//Connection accept
int sock_accept()
{
int s = sizeof(struct sockaddr_in);
d1= accept(sockfd, (struct sockaddr *)&client, (socklen_t*)&s);
if (d1 < 0)
{
perror("accept failed");
return 1;
}
puts("Connection accepted");
}
int main(int argc , char *argv[])
{ int client_sock;
sock_create();
sock_bind();
sock_listen();
sock_accept();
pthread_attr_t attr;
int i,j;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
printf("Creating threads\n");
int cli_sock=client_sock;
for (i = 0; i < NTHREADS ; i++)
{
pthread_create(&(thread_id[i]), &attr, connection_handler, (void*) &cli_sock);
}
pthread_attr_destroy(&attr); //Free attribute, wait for the other threads
for(j=0; j < NTHREADS; j++)
{
pthread_join( thread_id[j], NULL);
}
pthread_exit(NULL);
return 0;
}
void *connection_handler(void *sfd)
{
int sock = d1;
int read_size=0;
char *message , client_message[2000];
//Receive msg from client
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
{
client_message[read_size] = '\0';
//back to client
write(sock, client_message , strlen(client_message));
memset(client_message,'\0',sizeof(client_message));
memset(client_message, 0, 2000);
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("Recv failed");
}
pthread_mutex_lock(&lock);
service_count++;
pthread_mutex_unlock(&lock);
pthread_exit((void*) sfd);
return 0;
}
my client code is:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(int argc , char *argv[])
{
int sockfd;
struct sockaddr_in servaddr;
char msg[1000] , servaddr_reply[2000];
if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) <0)
{
printf("Could not create socket\n");
return 1;
}
puts("Socket created");
servaddr.sin_family= AF_INET;
servaddr.sin_port= htons(2100);
servaddr.sin_addr.s_addr= inet_addr("10.205.28.13");
if (connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) <0)
{
perror("Connection failed\n");
return 1;
}
puts("Connected");
while(1)
{
printf("Enter msg:");
scanf("%s" , msg);
if( send(sockfd , msg , strlen(msg) , 0) < 0)
{
puts("Send failed");
return 1;
}
// server reply
if( recv(sockfd, servaddr_reply , 2000 , 0) < 0)
{
puts("Recv failed");
break;
}
puts("Echo: ");
puts(servaddr_reply);
}
close (sockfd);
return 0;
}
now when my client is suppose sending hello server replies hello again if i enter message hi sever echoes back hillo .... cant figure out why?
Also why you take extra variables to assign socket descriptor? like int a, b, c, d? where you used? you used only global variable *d1 in your handler which is not initialized because
int sock_accept(int *d1) function give first priority to local one.
Also i see issue in your following code
int b = bind(sockfd, (struct sockaddr *) &server, sizeof(server));
^
|............. where you initialized?
same for below code
int d = accept(sockfd, (struct sockaddr *) &client, (socklen_t*) &s);
Also i see below meaning less code
sock_create(&a);
sock_bind(&b);
sock_listen(&c);
sock_accept(&d);
where you used a,b,c,d? because for communication you already taken sockfd and *d1.
You not need to pass any variable address to your function just make simple as follows
sock_create();
sock_bind();
sock_listen();
sock_accept();
And your code should be
int service_count, sockfd, d1;
// Socket create
int sock_create()
{
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
printf("Could not create socket");
return 1;
}
puts("Socket created");
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(2100);
}
// Bind
int sock_bind()
{
int b = bind(sockfd, (struct sockaddr *) &server, sizeof(server));
if (b < 0)
{
perror("Bind failed. Error");
return 1;
}
puts("Bind");
}
// Listen
int sock_listen()
{
listen(sockfd, 10);
}
//Connection accept
int sock_accept()
{
int s = sizeof(struct sockaddr_in);
d1 = accept(sockfd, (struct sockaddr *) &client, (socklen_t*) &s);
if (d1 < 0)
{
perror("accept failed");
return 1;
}
puts("Connection accepted");
}
now your handler should be
void *connection_handler(void *sfd)
{
int sock = d1;
int read_size = 0;
char *message, client_message[2000];
//Receive msg from client
while ((read_size = recv(sock, client_message, 2000, 0)) > 0)
{
client_message[read_size] = '\0';
//back to client
write(sock, client_message, strlen(client_message));
memset(client_message, '\0', sizeof(client_message));
memset(client_message, 0, 2000);
}
if (read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if (read_size == -1)
{
perror("Recv failed");
}
pthread_mutex_lock(&lock);
service_count++;
pthread_mutex_unlock(&lock);
pthread_exit((void*) sfd);
return 0;
}
int sock_accept(int *d1)
{
int s = sizeof(struct sockaddr_in);
int d= accept(sockfd, (struct sockaddr *)&client, (socklen_t*)&s);
d1=&d;
This makes d1 point to the local stack variable d. Once sock_accept returns, the value can be overwritten, and d1 will point to some random data. Try using *d1 = d instead, and pass an integer variable to sock_accept
You're making similar mistakes in other locations in your code as well.
Additionally: You have a global d1 variable which is never initialized. I think perhaps you should do some basic pointer stuff first, then proceed to deal with sockets, and then proceed to use threads instead of introducing a lot of unfamiliar topics at once.
Too many issues with the question code, this answer doesn't address the crash asked about but various other issues.
You try to free the pointer sfd at the end of your thread, but it's the address to client_sock which is on main's stack. That will most likely crash.
I think it's a good idea to let the creator of a resource destroy it, in general; e.g. if you hand an address to a function the function can generally not safely assume that it (a) points to dynamically allocated memory and (b) will not be used somewhere else later.
I have a simple tcp based client and server written in c, but once I establish a connection after the server sends a message back to the client, the connection stops working. Could you help me fix this - I would like the server to continue receiving/ sending messages to the client.
Code:
Server.c
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <unistd.h>
#define port 5000
#define buf 512
void answer(int);
int main(int argc, char *argv[]){
int sock = socket(AF_INET, SOCK_STREAM, 0);
int portid;
int backlog = 10;
struct sockaddr_in addr;
char BUFF[buf];
int n;
int received = 0;
int connfd;
if(sock == -1){
perror("socket error");
exit(errno);
}
memset(&addr,0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if(bind(sock, (struct sockaddr*) &addr, sizeof(addr)) == -1){
perror("bind error");
exit(errno);
}
if(listen(sock, backlog) == -1){
perror("listen error");
exit(errno);
}
listen(sock, 5);
struct sockaddr_in cliaddr;
//struct sockaddr_in addr;
int cliaddr_len = sizeof(cliaddr);
while(1){
connfd = accept(sock, (struct sockaddr*)&cliaddr,&cliaddr_len);
if(connfd == -1){
perror("error connfd");
exit(errno);
}
portid = fork();
if(portid<0)
perror("error on fork");
if(portid ==0){
close(sock);
answer(connfd);
exit(0);
}
//close(sock);
}
close(connfd);
return 0;
//close(sock);
//return 0;
}
void answer(int connfd){
int n;
char BUFF[buf];
memset(BUFF,buf,buf);
n = read(connfd,BUFF,buf);
printf("connected: %s",BUFF);
//received = 1;
//memset(BUFF,0,buf);
printf("please enter your message: ");
memset(BUFF,0,buf);
fgets(BUFF,buf, stdin);
n = write(connfd, BUFF,strlen(BUFF));
if(n<0) err("writing to socket problem");
}
Your server is calling fork, then if(portid ==0){...get and send message...}, then it loops back to the top of the loop where it tries to accept() --- not the job of the child, but the child is trying to do that anyway.
Refactor your code to do what you want. Break it into smaller parts that are simple for you to inspect so you can see things like this.
This is because you recv() data just one time. Use a loop to receive until the client disconnects.
while ((n = read(connfd,BUFF,buf))
{
printf("connected: %s",BUFF);
//received = 1;
//memset(BUFF,0,buf);
printf("please enter your message: ");
memset(BUFF,0,buf);
fgets(BUFF,buf, stdin);
n = write(connfd, BUFF,strlen(BUFF));
if(n<0) err("writing to socket problem");
}
You are reading the data in your child, so once the child is done the program exits, so try to read in the parent and send the data along to the child.