TCP Linux server lock after the first accept - c

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.

Related

Problems with UDP sockets and threads

I've run into a problem with UDP sockets.
For this particular program, a single .c file needs to be both a client to another server (via TCP) and a server/client to itself (executed twice, running on separate servers). It will be running twice at the same time and since it needs to be able to do both the TCP connection (for one type of data) and the UDP connection (for a different type of data) at the same time it needed to be done with threads or forks, but I used threads.
The issue I'm having is the UDP sockets aren't receiving any datagrams from each other. There are no compilation errors and it runs fine, but there's no output other than general debugging print statements. It's getting stuck at the recvfrom commands.
The code below is separated into two parts (again, within the same .c file). The top portion is the server section, and the lower portion is the client section. This is all done WITHIN a thread. I tried creating the socket THEN calling the thread with the client code (the idea was the thread would communicate with the parent but it didn't matter), but it gets the same result. So, for now, the thread just handles the UDP connection and the parent deals with the TCP.
If you need any more explanation, please feel free to ask. This is for a school assignment so I can't give TOO much, but I'll say what I can.
Thank you!
QUICK EDIT: All this code below is doing is just sending hello to the server and back to the client. Further details are not needed.
Assume that argv->stuff is the struct that I passed to the thread and that the user provides the server, IP address, and port when executing.
//----- Server portion of code is below
int cli2_sockfd;
char buffer_cli2[MAXLINE];
char *hello2 = "Hello from client 2";
struct sockaddr_in cli2_addr, client1_addr;
int clis_portno = atoi(argv->port);
clis_portno = clis_portno + 1;
// Creating socket file descriptor
if ( (cli2_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&cli2_addr, 0, sizeof(cli2_addr));
memset(&client1_addr, 0, sizeof(client1_addr));
// Filling server information
cli2_addr.sin_family = AF_INET; // IPv4
cli2_addr.sin_addr.s_addr = INADDR_ANY;
cli2_addr.sin_port = htons(clis_portno);
// Bind the socket with the server address
if ( bind(cli2_sockfd, (const struct sockaddr *)&cli2_addr,
sizeof(cli2_addr)) < 0 )
{
perror("bind failed");
exit(EXIT_FAILURE);
}
while(1)
{
int n2;
socklen_t len2;
if((n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE,
0, ( struct sockaddr *) &client1_addr,
&len2)) < 0)
{
perror("svr recvfrom");
exit(EXIT_FAILURE);
}
buffer_cli2[n2] = '\0';
printf("Client 1: %s\n", buffer_cli2);
if(sendto(cli2_sockfd, (const char *)hello2, strlen(hello2),
MSG_CONFIRM, (const struct sockaddr *) &client1_addr,
len2) < 0)
{
perror("svr sendto");
exit(EXIT_FAILURE);
}
printf("Hello message sent.\n");
}
//----- The client portion of the code is below
int client1_sockfd;
char buffer[MAXLINE];
char *hello1 = "Hello from client 1";
struct sockaddr_in client2_addr;
struct hostent *client_2;
clis_portno = atoi(argv->port);
clis_portno = clis_portno + 1;
// Creating socket file descriptor
if ( (client1_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&client2_addr, 0, sizeof(client2_addr));
if((client_2 = gethostbyname(argv->name)) == NULL)
{
perror("cli gethostbyname");
exit(EXIT_FAILURE);
}
bzero((char *) &client2_addr, sizeof(client2_addr));
// Filling Client 2 information
client2_addr.sin_family = AF_INET;
bcopy((char *)client_2->h_addr, (char *)&client2_addr.sin_addr.s_addr, client_2->h_length);
client2_addr.sin_port = htons(clis_portno);
while(1)
{
int n1;
socklen_t len1;
if( sendto(client1_sockfd, (const char *)hello1, strlen(hello1),
0, (const struct sockaddr *) &client2_addr,
sizeof(client2_addr)) < 0)
{
perror("cli sendto");
exit(EXIT_FAILURE);
}
printf("IN THREAD: Hello1 = %s\n", hello1);
if((n1 = recvfrom(client1_sockfd, (char *)buffer, MAXLINE,
MSG_WAITALL, (struct sockaddr *) &client2_addr,
&len1)) < 0)
{
perror("cli recvfrom");
exit(EXIT_FAILURE);
}
buffer[n1] = '\0';
printf("IN THREAD: Client 2 : %s\n", buffer);
}
You are forgetting to initialize len2:
socklen_t len2;
if((n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE,
0, ( struct sockaddr *) &client1_addr,
&len2)) < 0)
Better:
socklen_t len2 = sizeof(client1_addr);
n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE,
0, ( struct sockaddr *) &client1_addr,
&len2));
if (n2 < 0)
{
….
Not sure if that's your only issue that's preventing packets from being received.
I cleaned up your code a little and got it to work using port 9999 for server. And having the client connect to localhost. I cleaned up some of those memcpy statements around gethostbyname, some of your struct initialization calls, removed some of the exit calls that could occur for benign errors (including recvfrom errors when the server is offline). That MSG_WAITALL flag looked weird, so I removed that as well.
I got it working Cygwin without any special hacks. I have no doubt it would work in Linux (or any Unix).
You can see it working here in server mode:
And the corresponding window in client mode:
Code here:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <stdlib.h>
#include <memory.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <stdarg.h>
#define MAXLINE 260
#define MSG_CONFIRM "Confirm"
void server(unsigned short port)
{
int cli2_sockfd = -1;
char buffer_cli2[MAXLINE] = { 0 };
char *hello2 = "Hello from client 2";
struct sockaddr_in cli2_addr = { 0 }, client1_addr = { 0 };
unsigned short clis_portno = port;
// Creating socket file descriptor
if ((cli2_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// Filling server information
cli2_addr.sin_family = AF_INET; // IPv4
cli2_addr.sin_addr.s_addr = INADDR_ANY;
cli2_addr.sin_port = htons(clis_portno);
// Bind the socket with the server address
if (bind(cli2_sockfd, (const struct sockaddr *)&cli2_addr,
sizeof(cli2_addr)) < 0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
while (1)
{
int n2;
socklen_t len2 = sizeof(client1_addr);
if ((n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE,
0, (struct sockaddr *) &client1_addr,
&len2)) < 0)
{
perror("svr recvfrom");
exit(EXIT_FAILURE);
}
buffer_cli2[n2] = '\0';
printf("Client 1: %s\n", buffer_cli2);
if (sendto(cli2_sockfd, (const char *)hello2, strlen(hello2),
0, (const struct sockaddr *) &client1_addr,
len2) < 0)
{
perror("svr sendto");
}
printf("Hello message sent.\n");
}
}
void client(const char* hostname, unsigned short port)
{
int client1_sockfd;
char buffer[MAXLINE];
char *hello1 = "Hello from client 1";
struct sockaddr_in client2_addr = { 0 };
struct hostent *client_2 = NULL;
unsigned short clis_portno = port;
// Creating socket file descriptor
if ((client1_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
if ((client_2 = gethostbyname(hostname)) == NULL)
{
perror("cli gethostbyname");
exit(EXIT_FAILURE);
}
// Filling Client 2 information
client2_addr.sin_family = AF_INET;
client2_addr.sin_port = htons(clis_portno);
memcpy(&client2_addr.sin_addr, client_2->h_addr, 4);
while (1)
{
int n1;
if (sendto(client1_sockfd, (const char *)hello1, strlen(hello1),
0, (const struct sockaddr *) &client2_addr,
sizeof(client2_addr)) < 0)
{
perror("cli sendto");
exit(EXIT_FAILURE);
}
printf("IN THREAD: Hello1 = %s\n", hello1);
socklen_t len1 = sizeof(client2_addr);
if ((n1 = recvfrom(client1_sockfd, (char *)buffer, MAXLINE,
0, (struct sockaddr *) &client2_addr,
&len1)) < 0)
{
perror("cli recvfrom");
}
else
{
buffer[n1] = '\0';
printf("IN THREAD: Client 2 : %s\n", buffer);
}
sleep(1);
}
}
int main(int argc, char** argv)
{
if ((argc > 1) && (strcmp(argv[1], "s") == 0))
{
printf("Running in server mode\n");
server(9999);
}
else
{
printf("Running in client mode\n");
client("localhost", 9999);
}
return 0;
}

client server communication is not happening. The client code is not displaying after send function

I don't know whether the problem is with the client or with the server or both.This is my first client-server socket programming code. But this is not working as expected. The code which I referenced is working well although.
When the code runs, the client and server should both exchange 2 messages, but they are not doing so. The server is displaying "Listening" which is right as expected but when I run the client code, Nothing happens, It just displays nothing.
This is the client code
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
int main() {
struct sockaddr_in mysocket, servsocket;
int err;
char buf[256];
//CREATING SOCKET
int socketstatus = socket(AF_INET, SOCK_STREAM, 0);
printf("%d\n", socketstatus);
if(socketstatus < 0){
printf("socket failed\n");
scanf("%d", &err);
return 0;
}
bzero((char *) &mysocket, sizeof(mysocket));
mysocket.sin_family = AF_INET;
mysocket.sin_addr.s_addr = inet_addr("127.0.0.2");
int port = 5674;
mysocket.sin_port = htons(port);
//CONNECT
int connectstatus = connect(socketstatus, (struct sockaddr *) &servsocket, sizeof(servsocket));
if(connectstatus < 0){
printf("Connect failed\n");
scanf("%d", &err);
return 0;
}
//SEND
bzero(buf, 256);
strcpy(buf, "Message sent by client");
int sendstatus = send(socketstatus, buf, 256, 0);
printf("2\n"); //This is not being displayed
if(sendstatus < 0){
printf("Client send failed\n");
return 0;
}
printf("Reached for receiving\n");
//RECEIVE
bzero(buf, 256);
int recvstatus = recv(socketstatus, buf, 256, 0);
if(recvstatus < 0){
printf("Client RECEIVE failed\n");
scanf("%d", &err);
return 0;
}
printf("The message client got from server is, %s \n",buf );
scanf("%d", &err);
printf("Bye");
}
And this is the server code:
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
int main() {
int err;
struct sockaddr_in servsocket, clientsocket;
char sendmessage[256];
//CREATING SOCKET
int mysocket = socket(AF_INET, SOCK_STREAM, 0);
if(mysocket < 0){
printf("socket creation failed\n");
scanf("%d", &err);
return 0;
}
bzero((char*) &servsocket, sizeof(servsocket)); //initiazlizing servsocket with null
servsocket.sin_family = AF_INET;
servsocket.sin_addr.s_addr = inet_addr("127.0.0.2");
int port = 5674;
servsocket.sin_port = htons(port);
//BINDING
int bindstatus = bind(mysocket, (struct sockaddr*) &servsocket, sizeof(servsocket));
if(bindstatus < 0){
printf("Socket bind failed\n");
scanf("%d", &err);
return 1;
}
//LISTENING
int listenstatus = listen(mysocket, 5);
if(listenstatus < 0){
scanf("%d", &err);
return 2;
}
else
printf("LISTENING....\n");
//ACCEPTING
int clientsize = sizeof(clientsocket);
int acceptstatus = accept(mysocket, (struct sockaddr*) &clientsocket, &clientsize);
if(acceptstatus < 0){
printf("Accept failed");
scanf("%d", &err);
return 3;
}
char buf[256];
bzero(buf, 256);
//RECEIVING
int recvstatus = recv(acceptstatus, buf, 256, 0);
if(buf < 0){
printf("Error:Nothing read");
scanf("%d", &err);
return 4;
}
printf("I received this message, %s \n", buf);
printf("NOW I WILL SEND\n");
//SENDING
bzero(sendmessage, 256);
strcpy(sendmessage, "Message sent by server");
int sendstatus = send(acceptstatus, sendmessage, sizeof(sendmessage), 0);
if(sendstatus < 0){
printf("Error sending\n");
scanf("%d", &err);
return 5;
}
return 0;
}
In the client code, you initialize mysocket but pass serversocket to connect uninitialized.
You should be setting the fields of serversocket instead of mysocket.
You want to connect to the server socket inside your client (that would be serversocket in your code, not mysocket):
bzero((char *) &servsocket, sizeof(servsocket));
servsocket.sin_family = AF_INET;
servsocket.sin_addr.s_addr = inet_addr("127.0.0.2");
int port = 5674;
servsocket.sin_port = htons(port);
Then, I think you want your inet address to be 127.0.0.1 (what is typically default localhost address), not 127.0.0.2.
The code was "working" because you were passing a correct socket descriptor (socketstatus) to it is not correctly connected to the endpoint, so it fails on the send() call.

Socket programming client server message read write in C

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.

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.

Server prints to stdout instead of socket

I am working through examples in UNIX Network Programming and I've adapted "daytimeclientserv.c" into this code here. The server sends the date/time string to the client as expected except for the very first request it receives upon starting up. When I first run the server program (on another computer in the LAN) it creates the listening socket, binds it and then waits for connections. Upon receiving the first request it prints the date/time string to its own stdout (terminal) instead of to the socket and the client program hangs forever waiting. However, all subsequent requests are sent to the clients correctly. Using gdb, I noticed that connfd is always set to zero. It is set to zero on the first request and also on all future ones.
I also have a few other questions related to this:
if the server listens on one socket (listenfd) and then reconnects on another (connfd) with connect(), how does the client deal with the change of socket? It was my understanding that a socket is uniquely identified by four parts: servIPaddr, servPort, clientIPaddr, clientPort
how can i run the server (on linux) without being root
how can i cleanly close the listening socket, so that i can use it again. I get a bind error if I quit the server program with SIGINT (Ctrl-C). So far I've been using gdb, and using a "call close(listenfd)" to manually call the function. But is there a way to do this if I am not using gdb (ie. debugging the client application only).
Any help is greatly appreciated.
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#define BUFFER 80
int main(int argc, char **argv) {
int listenfd, connfd;
char buf[BUFFER];
struct sockaddr_in servaddr;
time_t ticks;
struct sockaddr *ptr;
char *ret;
if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket error");
return 1;
}
memset(&servaddr, 0, sizeof(servaddr));
memset(buf, 0, BUFFER);
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
ptr = (struct sockaddr*) &servaddr;
if ( bind(listenfd, ptr ,sizeof(servaddr)) < 0) {
perror("bind error");
return 2;
}
if ( listen(listenfd, 128) < 0) {
perror("listen error");
return 3;
}
ptr = NULL;
while ( 1 ) {
if ( connfd = accept(listenfd, ptr, NULL) < 0) {
perror("accept error");
return 4;
} else {
ticks = time(NULL);
ret = ctime(&ticks);
sprintf(buf, "%.24s\n", ret);
if ( write(connfd, buf, strlen(buf)) < 0) {
perror("write error");
close(connfd);
}
}
return 0;
}
Here was my hunch: On a terminal (tty), stdout and stdin are the same physical device. Therefore writing to filedescriptor 0 (stdin) might actually work and result in terminal output.
You need parentheses around this
if ( connfd = accept(listenfd, ptr, NULL) < 0) {
Like so
if ( (connfd = accept(listenfd, ptr, NULL)) < 0) {
Or connfd will be assigned '0'
Update Just tested this, and this is indeed the culprit. Next time, compile with gcc -Wall and the compiler would have told you this (and several other issues of good form/style). That way, you won't have to rely on having the hunch to find the error.
Fixed version:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#define BUFFER 80
int main(int argc, char **argv) {
int listenfd, connfd;
char buf[BUFFER];
struct sockaddr_in servaddr;
time_t ticks;
struct sockaddr *ptr;
char *ret;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if ( listenfd < 0 ) {
perror("socket error");
return 1;
}
memset(&servaddr, 0, sizeof(servaddr));
memset(buf, 0, BUFFER);
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
ptr = (struct sockaddr*) &servaddr;
if ( bind(listenfd, ptr ,sizeof(servaddr) ) < 0) {
perror("bind error");
return 2;
}
if ( listen(listenfd, 128) < 0 ) {
perror("listen error");
return 3;
}
ptr = NULL;
while ( 1 ) {
connfd = accept(listenfd, ptr, NULL);
if ( connfd < 0 ) {
perror("accept error");
return 4;
} else {
ticks = time(NULL);
ret = ctime(&ticks);
sprintf(buf, "%.24s\n", ret);
if ( write(connfd, buf, strlen(buf)) < 0) {
perror("write error");
close(connfd);
}
}
}
return 0;
}

Resources