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;
}
Related
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;
}
I wrote a simple TCP echo server to handle multiple clients. It uses select() to get multiple connections.
Server Code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
int create_listener(uint16_t port) {
int listen_fd;
struct sockaddr_in name;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) {
perror ("socket");
exit(EXIT_FAILURE);
}
bzero(&name, sizeof(name));
name.sin_family = AF_INET;
name.sin_addr.s_addr = htonl(INADDR_ANY);
name.sin_port = htons(port);
if (bind(listen_fd, (struct sockaddr *) &name, sizeof(name)) < 0) {
perror ("bind");
exit(EXIT_FAILURE);
}
return listen_fd;
}
int read_from_client(int fd) {
char buffer[100];
int nbytes;
nbytes = read(fd, buffer, 100);
if (nbytes < 0) {
perror("read");
exit(EXIT_FAILURE);
}
else if (nbytes == 0) {
return -1;
}
else {
fprintf(stderr, "Server: got message: %s\n", buffer);
write(fd, buffer, strlen(buffer) + 1);
return 0;
}
}
int main(int argc, char *argv[]) {
int listen_fd;
uint16_t port = 22000;
fd_set active_fd_set, read_fd_set;
int i;
struct sockaddr_in servaddr;
/* Create the socket and set it up to accept connections. */
listen_fd = create_listener(port);
if (listen(listen_fd, 10) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
/* Initialize the set of active sockets. */
FD_ZERO(&active_fd_set);
FD_SET(listen_fd, &active_fd_set);
while (1) {
/* Block until input arrives on one or more active sockets. */
read_fd_set = active_fd_set;
if (select(FD_SETSIZE, &read_fd_set, NULL, NULL, 0) < 0) {
perror("select");
exit(EXIT_FAILURE);
}
/* Service all the sockets with input pending. */
for (i = 0; i < FD_SETSIZE; ++i) {
if (FD_ISSET(i, &read_fd_set)) {
if (i == listen_fd) {
/* Connection request on original socket. */
int new_fd;
new_fd = accept(listen_fd, (struct sockaddr *) NULL, NULL);
if (new_fd < 0) {
perror ("accept");
exit(EXIT_FAILURE);
}
FD_SET(new_fd, &active_fd_set);
}
else {
/* Data arriving on an already-connected socket. */
if (read_from_client(i) < 0) {
close(i);
FD_CLR(i, &active_fd_set);
}
}
}
}
}
return 0;
}
Client code:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int sockfd, n;
char sendline[100];
char recvline[100];
struct sockaddr_in servaddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(22000);
inet_pton(AF_INET, "127.0.0.1", &(servaddr.sin_addr));
connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
while (1) {
bzero(sendline, 100);
bzero(recvline, 100);
fgets(sendline, 100, stdin);
write(sockfd, sendline, strlen(sendline) + 1);
read(sockfd, recvline, 100);
printf("%s", recvline);
}
return 0;
}
The problem is when I run server in one terminal and run two clients in another two terminals. If I use Ctrl+C to terminate one client, the server automatically terminates. I'm wondering why the server acts this way. What I'm expecting is the server runs forever. When client 1 terminates, server should still has a live connection with client 2.
Looks like you're hitting the exit in read_from_client. In general, in a server that serves multiple clients, you probably don't want to exit when you have a failure with one of the client connections.
I am beginner in socket programming and reading Linux Network Programming book. I decided to implement client-server connection as shown in the book. Server program is run on Ubuntu 14.04 machine and client code is run from Mac machine. The server code is the following
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
const char message[] = "hello, world\n";
int main()
{
int sock = 0;
int port = 0;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
fprintf(stderr, "failed\n");
else
printf("connection is establisshed\n");
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY );
server.sin_port = 3500;
int status = bind(sock, (struct sockaddr*) &server, sizeof(server));
if (status == 0)
printf("connection completed\n");
else
printf("problem is encountered\n");
status = listen(sock, 5);
if (status == 0)
printf("app is ready to work\n");
else
{
printf("connection is failed\n");
return 0;
}
while (1)
{
struct sockaddr_in client = { 0 };
int sclient = 0;
int len = sizeof(client);
int childSocket = accept(sock, (struct sockaddr*) &client, &len);
if (childSocket == -1)
{
printf("cannot accept connection\n");
close(sock);
break;
}
write(childSocket, message, strlen(message));
close(childSocket);
}
return 0;
}
As for client side i wrote the following code
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
int main(int argc, char* argv[])
{
int sock = 0;
int port = 0;
struct sockaddr_in servaddr;
sock = socket(AF_INET, SOCK_STREAM, 0);
int status = 0;
char buffer[256] = "";
if (sock == -1)
{
printf("could not establish connection\n");
exit(1);
}
port = 3500;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
servaddr.sin_port = htons(port);
status = connect(sock, (struct sockaddr*) &servaddr, sizeof(servaddr));
if (status == 0)
printf("connection is established successfully\n");
else
{
printf("could not run the app\n");
exit(1);
}
status = read(sock, buffer, sizeof(buffer));
if (status > 0)
printf("%d: %s", status, buffer);
close(sock);
return 0;
}
To get IP address of client machine I run ifconfig from terminal an get inet_addr 192.168.1.165 value. Now when I pass that address string as command line argument I get message that app is not running message. There is problem with address that I got, as I understand. So what is the problem?
Thanks in advance
Most probably the server does not listen on the port you are assuming, that is 3500.
To fix this, change this line:
server.sin_port=3500
to be
server.sin_port = htons(3500);
(To monitor which process is listing on which address:port you might like to use the netstat command line tool. In your case probably using the options -a -p -n )
Also on recent systems accept() expects a pointer to socklen_t as last parameter, so change this
int len=sizeof(client);
to be
socklen_t len = sizeof client; /* sizeof is an operator, not a function¨*/
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.