I have this program that is a part of a server with tcp protocol, that gets a number from the client and uses it in another function.
Also I have a static int type variable that i want to count each time the server gets a message from a client, but each time it does not keep its value;
The variable is counter
Can you guys tell me why this is happening?
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// used port
#define PORT 1114
// error code
extern int errno;
static int counter;
int main ()
{
struct sockaddr_in server; // structure used by server
struct sockaddr_in from;
char message[100]; //message received from client
int socketDescriptor; //socket descriptor
//creating socket
if ((socketDescriptor = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("[server]Error at socket\n");
return errno;
}
//preparing data structures
bzero (&server, sizeof (server));
bzero (&from, sizeof (from));
//filling structures
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl (INADDR_ANY);
server.sin_port = htons (PORT);
//attach socket to descriptor
if (bind (socketDescriptor, (struct sockaddr *) &server, sizeof (struct sockaddr)) == -1)
{
perror ("[server]Error at bind\n");
return errno;
}
//server is listening
if (listen (socketDescriptor, 2) == -1)
{
perror ("[server]Error at listen\n");
return errno;
}
/serving concurrent the clients
while (1)
{
int client;
int length = sizeof (from);
printf ("[server]Waiting at port %d...\n",PORT);
fflush (stdout);
//accepting client
client = accept (socketDescriptor, (struct sockaddr *) &from, &length);
counter ++;
switch(fork())
{
case -1:
perror("fork err\n");
exit(2);
case 0:
//error if failed connection
if (client < 0)
{
perror ("[server]Error at accept\n");
continue;
}
//conenction established
bzero (message, 100);
printf ("[server]Waiting for message...\n");
fflush (stdout);
//reading message
if (read (client, message, 100) <= 0)
{
perror ("[server]Error at read\n");
close (client); //closing connection
continue; //keep listening
}
printf ("[server]Message was received%s\n", message);
//this is where I want to increment counter, when I want to verify message
int number;
number = atoi(message);//convert char to int
printf("The number is: %d\n", number);//print number
printf("The counter is : %d\n", counter);
fflush(stdout);
exit(2);
}
close (client);
} /* while */
} /* main */
Just move counter++ to the parent process. When the child process starts it gets a copy of counter and the one you modify does not affect it's copy (original actually) in the parent process. If you update it in the parent process you will achieve what you want.
int main(int argc, char ** argv)
{
int number;
int listenfd, connfd, n;
pid_t childpid;
socklen_t clilen;
char message[MAXLINE], answer[MAXLINE];
struct sockaddr_in clientaddr, serveraddr;
int counter;
counter = 0;
// create socket
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("ERROR at creating socket\n");
exit(2);
}
// preparation of socket address
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(PORT);
// bind the socket
bind(listenfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr));
// listen to the socket
listen(listenfd, LIMIT);
printf("Server running, waiting for connections at port : %d\n", PORT);
while (1)
{
clilen = sizeof(clientaddr);
// accept a connection
connfd = accept(listenfd, (struct sockaddr *) &clientaddr, &clilen);
printf("Recieved guest\n");
switch (fork())
{
case -1:
perror("fork err\n");
exit(2);
case 0:
/* eroare la acceptarea conexiunii de la un client */
if (connfd < 0)
{
perror("[server]Eroare la accept().\n");
continue;
}
/* s-a realizat conexiunea, se astepta mesajul */
bzero(message, 100);
printf("[server]Asteptam mesajul...\n");
fflush(stdout);
/* citirea mesajului */
if (read(connfd, message, 100) <= 0)
{
perror("[server]Eroare la read() de la client.\n");
close(connfd); /* inchidem conexiunea cu clientul */
continue; /* continuam sa ascultam */
}
printf ("[server]Message was received...%s\n", message);
fflush(stdout);
number = atoi(message);
printf("The number is: %d\n", number);
printf ("%d\n", counter + 1);
_exit(0); // The child should not create further grand children
default:
counter++;
break;
}//switch
}//for
close(connfd);
}//main
You appear to be forking before setting the counter. Since forking duplicates the entire process, the copy of counter in each child process is different from the parent.
Sharing variables between applications in C can be tricky, but actually there's a pretty easy fix for your case and it will improve performance too. If you look at your code, you're forking after the connect and then handling, in the child, the possibiliy that the connfd < 0. If you handled that in the parent process, the counter could belong to the parent and could be incremented before the fork.
A few other notes here come to mind. Remember, fork duplicates the parent process, so the children in your case are still within a while(1) loop. When you continue you loop back to the next iteration of the while(1) loop, but this doesn't seem correct; you want the child process to exit when it's done handling the connection. This also means as you accept connections, you fork but the fork never dies - I guess that's more a "process leak" than a memory leak, but will certainly eat up memory. Finally, just to throw it out there, forking to handle each request is probably the slowest way to concurrently handle connections. I've had great success with pthread in this case. Since threads share a process space, the threads can even persist and handle many connections before dying ( put the connections on a queue and have the threads poll it, for example ) becasuse they can continue to share connections with their "parent" ( though it's really a sibling thread in this case).
Related
I am working on a server-client project which allows the server to exchange messages
with a client individually. However, I have to modify the server so that when the server sends a message, it is sent to all connected clients.
I know this involves sharing variables among threads but I am confused on how to go about do this?
Any tips/guidence will be appreciated!
Server Code:
#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
#define MAX 80
#define PORT 6543
#define SA struct sockaddr
// Function designed for chat between client and server.
void join( pthread_t *thread_id)
{
if(!pthread_join( *thread_id , NULL))
printf("thread %ld complted\n",*thread_id);
pthread_exit(0);//to exit the current thread
}
void func(int *sockfd)
{
char buff[MAX];
int n;
// infinite loop for chat
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
read(*sockfd, buff, sizeof(buff));
// print buffer which contains the client contents
printf("From client: %s\t To client : ", buff);
bzero(buff, MAX);
n = 0;
// copy server message in the buffer
while ((buff[n++] = getchar()) != '\n');
// and send that buffer to client
write(*sockfd, buff, sizeof(buff));
// if msg contains "Exit" then server exit and chat ended.
if (strncmp("exit", buff, 4) == 0) {
printf("Server Exit...\n");
break;
}
}
}
// Driver function
int main()
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
pthread_t thread_id,jointhread_id;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
len = sizeof(cli);
// Accept the data packet from client and verification
while(connfd = accept(sockfd, (SA*)&cli, &len))
{
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client..%d.\n",connfd);
if( pthread_create( &thread_id , NULL , func , (void*) &connfd) < 0)
{
perror("could not create thread");
return 1;
}
if( pthread_create( &jointhread_id , NULL , join , (void*) &thread_id) < 0)
{
perror("could not create thread");
return 1;
}
}
// After chatting close the socket
close(sockfd);
}
Unfortunately, there were a number of bugs ...
Wrong prototype for thread functions
Race condition for connfd as mentioned in my top comments (passing connfd to func as a pointer).
Doing getchar destroys the message data from the read of sockfd
I've produced a version below that illustrates this.
But, to actually get the code closer to what is required for your stated purpose, required a fair amount of refactoring. There's a second version further down that illustrates my take on that.
Here's an annotated version that shows the bugs and some fixes [mostly what it took to get it to compile cleanly].
It wraps original code with #if ORIG and new code with #if FIX and each place has a comment about the bug it's fixing
#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
#define MAX 80
#define PORT 6543
#define SA struct sockaddr
#define ORIG 0
#define FIX 1
// Function designed for chat between client and server.
// NOTE/BUG -- the main thread has to join the thread
#if ORIG
void
join(pthread_t *thread_id)
{
if (!pthread_join(*thread_id, NULL))
printf("thread %ld complted\n", *thread_id);
// to exit the current thread
pthread_exit(0);
}
#endif
// NOTE/BUG: this is the _wrong_ signature for a thread function
#if ORIG
void
func(int *sockfd)
#else
void *
func(void *ptr)
#endif
{
#if FIX
int sockfd = (long) ptr;
#endif
char buff[MAX];
int n;
// infinite loop for chat
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
// NOTE/BUG: this has a race condition
// NOTE/BUG: we need the actual length
#if ORIG
read(*sockfd, buff, sizeof(buff));
#else
int rlen = read(sockfd, buff, sizeof(buff));
#endif
// print buffer which contains the client contents
printf("From client: %s\t To client : ", buff);
bzero(buff, MAX);
// copy server message in the buffer
// NOTE/BUG: this is destroying the data that was
#if ORIG
n = 0;
while ((buff[n++] = getchar()) != '\n');
#endif
// and send that buffer to client
#if ORIG
write(*sockfd, buff, sizeof(buff));
#else
write(sockfd, buff, rlen);
#endif
// if msg contains "Exit" then server exit and chat ended.
if (strncmp("exit", buff, 4) == 0) {
printf("Server Exit...\n");
break;
}
}
// NOTE/BUG: we must return the error code
#if FIX
return (void *) 0;
#endif
}
// Driver function
int
main()
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
pthread_t thread_id, jointhread_id;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
// assign IP, PORT
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA *) & servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
// Accept the data packet from client and verification
len = sizeof(cli);
// NOTE/BUG: connfd can be zero for a valid connection
#if ORIG
while (connfd = accept(sockfd, (SA *) &cli, &len)) {
#else
while (1) {
connfd = accept(sockfd, (SA *) &cli, &len);
#endif
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client..%d.\n", connfd);
#if ORIG
if (pthread_create(&thread_id, NULL, func, (void *) &connfd) < 0) {
perror("could not create thread");
return 1;
}
#else
if (pthread_create(&thread_id, NULL, func, (void *) ((long) connfd)) < 0) {
perror("could not create thread");
return 1;
}
#endif
// NOTE/BUG -- creating a separate thread just to join the above thread does
// not help
#if ORIG
if (pthread_create(&jointhread_id, NULL, join, (void *) &thread_id) < 0) {
perror("could not create thread");
return 1;
}
#endif
}
// After chatting close the socket
close(sockfd);
return 0;
}
Here's a refactored version that implements the multiple client message echo that you wanted.
It uses a per-thread task block to control things. Each client, when it receives a message, sends it all other clients.
It also does a bit of interthread locking using mutexes.
Having a given client thread do all the echo to the other clients is but one way to do this. There are others (e.g. all client threads queue the message to the master/main thread and it does the echo)
This is a lot closer but you'll have more work to do in func to receive/send the client message.
Anyway, here is the code:
#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
#define MAX 80
#define PORT 6543
#define SA struct sockaddr
#define ORIG 0
#define FIX 1
enum {
TSKSTATE_IDLE, // task slot free/available
TSKSTATE_PENDING, // task is being created
TSKSTATE_RUNNING, // task is alive and running
TSKSTATE_DONE // task has completed (but not reaped)
};
typedef struct tsk tsk_t;
struct tsk {
tsk_t *tsk_next; // chain pointer
pthread_t tsk_tid; // thread id
long tsk_xid; // sequential task id
int tsk_sockfd; // client socket descriptor
int tsk_state; // current task state
pthread_mutex_t tsk_mutex; // per-thread mutex
void *tsk_rtn; // thread's return value
};
// NOTE: using an array obviates the need for a master lock if we used a
// linked list here instead -- by passing TSKMAX to listen below [in main],
// we guarantee that main can always find a free task slot when it needs one
#define TSKMAX 5
tsk_t tsklist[TSKMAX]; // active task list
#define TSKFORALL(_tsk) \
_tsk = &tsklist[0]; _tsk < &tsklist[TSKMAX]; ++_tsk
long tskxid; // sequential task id
__thread tsk_t *tskcur; // current thread's tsk block
pthread_mutex_t master_lock = PTHREAD_MUTEX_INITIALIZER;
// lockall -- lock all threads
void
lockall(void)
{
pthread_mutex_lock(&master_lock);
}
// unlockall -- lock all threads
void
unlockall(void)
{
pthread_mutex_unlock(&master_lock);
}
// tsklock -- lock single thread
void
tsklock(tsk_t *tsk)
{
pthread_mutex_lock(&tsk->tsk_mutex);
}
// tskunlock -- unlock single thread
void
tskunlock(tsk_t *tsk)
{
pthread_mutex_unlock(&tsk->tsk_mutex);
}
// tskreapall -- release all completed threads
void
tskreapall(void)
{
tsk_t *tsk;
lockall();
for (TSKFORALL(tsk)) {
tsklock(tsk);
if (tsk->tsk_state == TSKSTATE_DONE) {
pthread_join(tsk->tsk_tid,&tsk->tsk_rtn);
tsk->tsk_state = TSKSTATE_IDLE;
}
tskunlock(tsk);
}
}
// tsksendall -- send message to all other clients
void
tsksendall(char *msg,int len)
{
tsk_t *tsk;
lockall();
for (TSKFORALL(tsk)) {
if (tsk == tskcur)
continue;
tsklock(tsk);
if (tsk->tsk_state == TSKSTATE_RUNNING)
write(tsk->tsk_sockfd,msg,len);
tskunlock(tsk);
}
}
void *
func(void *ptr)
{
tskcur = ptr;
char buff[MAX];
#if ORIG
int n;
#endif
tsklock(tskcur);
tskcur->tsk_state = TSKSTATE_RUNNING;
tskunlock(tskcur);
// infinite loop for chat
// NOTE: this loop still needs work ...
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
int rlen = read(tskcur->tsk_sockfd, buff, sizeof(buff));
// print buffer which contains the client contents
printf("From client: %s\t To client : ", buff);
bzero(buff, MAX);
// copy server message in the buffer
// NOTE/BUG: this is destroying the data that was
#if ORIG
n = 0;
while ((buff[n++] = getchar()) != '\n');
#endif
// and send that buffer to client
write(tskcur->tsk_sockfd, buff, rlen);
// if msg contains "Exit" then server exit and chat ended.
if (strncmp("exit", buff, 4) == 0) {
printf("Server Exit...\n");
break;
}
// echo message to all other clients
tsksendall(buff,rlen);
}
tsklock(tskcur);
tskcur->tsk_state = TSKSTATE_DONE;
close(tskcur->tsk_sockfd);
tskcur->tsk_sockfd = -1;
tskunlock(tskcur);
return (void *) 0;
}
// Driver function
int
main(void)
{
int sockfd, connfd;
socklen_t len;
struct sockaddr_in servaddr, cli;
int state;
tsk_t *tsktry;
tsk_t *tsknew;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
// assign IP, PORT
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA *) & servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, TSKMAX)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
// Accept the data packet from client and verification
len = sizeof(cli);
for (TSKFORALL(tsktry)) {
pthread_mutex_init(&tsktry->tsk_mutex,NULL);
tsktry->tsk_state = TSKSTATE_IDLE;
}
while (1) {
connfd = accept(sockfd, (SA *) &cli, &len);
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client..%d.\n", connfd);
// reap all completed threads
tskreapall();
// find an idle slot
tsknew = NULL;
for (TSKFORALL(tsktry)) {
tsklock(tsktry);
state = tsktry->tsk_state;
if (state == TSKSTATE_IDLE) {
tsknew = tsktry;
tsknew->tsk_state = TSKSTATE_PENDING;
}
tskunlock(tsktry);
if (tsknew != NULL)
break;
}
tsknew->tsk_xid = ++tskxid;
tsknew->tsk_sockfd = connfd;
if (pthread_create(&tsknew->tsk_tid, NULL, func, tsknew) < 0) {
perror("could not create thread");
return 1;
}
}
// After chatting close the socket
close(sockfd);
return 0;
}
I'm trying make the program run multiple threads to it connects to different ports. I successfully made it work on a single thread but not multiple.
Below I have posted the code of what I'm using on XUbuntu.
server.c
#include <stdio.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
// File io storing in lof file
#include "server_portLog.h"
// Thread used to create sockets
#include "sockets_pthread.h"
#define BUFFER_SIZE 1024
int main(int argc, char *argv[]) {
// Server port number
//int portNumber = atoi(argv[1]);
// sockfd: ip-address socket, newsockfd: socket from receiving client, portNum: Which port will be listening, num_bytes: received data from client
int sockfd, newsockfd, num_bytes;
// buffer: will send & receive values from the server
char buffer[BUFFER_SIZE];
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen = sizeof(cli_addr);
// Getting all ports from command line parameters and creating a socket for each
int numPorts = argc - 1;
struct port varPorts[numPorts];
pthread_t portsSockets[numPorts];
for (int i = 0; i < numPorts; i++) {
varPorts[i].portNumber = atoi(argv[i + 1]);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&portsSockets[i], &attr, createSocket, &varPorts[i]);
}
// Infinite loop too keep listening even after connection to client closes
while (1) {
// After that all the ports entered have a socket of their own the program runs them parallel together to see if any client tries to connect with one of the ports
for (int i = 0; i <= numPorts; i++) {
pthread_join(&portsSockets[i], NULL);
/* Start listening for the clients (thread blocks) */
if (listen(varPorts[i].sockfd, 5) != 0) {
printf("Error: listen() failed for port: %d \n", varPorts[i].portNumber);
//return 3;
}
// Accepting connection from client & creating socket with that client data
newsockfd = accept(varPorts[i].sockfd, (struct sockaddr *)&cli_addr, &clilen);
if (newsockfd < 0) {
printf("Error: accept() failed for port: %d \n", varPorts[i].portNumber);
//return 4;
}
/* To send receive data */
// Clearing buffer
memset(buffer, 0, BUFFER_SIZE);
// Show data received from client
num_bytes = recv(newsockfd, buffer, BUFFER_SIZE-1, 0);
if (num_bytes < 0) {
printf("Error: recv() failed for port: %d \n", varPorts[i].portNumber);
//return 5;
}
// Checking version of server if LOGFILE it creates a file to store the ports
#if defined LOGFILE
// Checking if user wrote a fileName for the logs or going to use the default log file
if (argc == 3) {
char *textFile = argv[argc-1];
serverLogFile_Custom(buffer, textFile);
}
else {
serverLogFile_Defualt(buffer);
}
#else
// Print the port numbers that connect to server
printf("Received: Client using port- %s to connect \n", buffer);
#endif
// Closing connection with client
close(newsockfd);
}
}
return 0;
}
Sockets_pthreads.h
#include <pthread.h>
struct port {
int portNumber;
int sockfd;
};
void* createSocket(void* portNumber) {
// sockfd: ip-address socket, newsockfd: socket from receiving client, portNum: Which port will be listening, num_bytes: received data from client
int sockfd, newsockfd, num_bytes;
// buffer: will send & receive values from the server
//char buffer[BUFFER_SIZE];
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen = sizeof(cli_addr);
struct port *portStruct = (struct port*) portNumber;
// Creating a new socket with ip-Protocol_tcp
// Parameters: Internet-domain, socket-stream, TCP-protocol
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0) {
printf("Error: Failed to open socket for port: %d \n", portStruct->portNumber);
//return 1;
}
// Setting all bits in padding-field to 0
memset(&serv_addr, 0, sizeof(serv_addr));
// Initializing socket in sockaddr_in (stucture)
serv_addr.sin_family = AF_INET; // Seting family-Internet
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(portStruct->portNumber); // Setting portNum (passed in command line)
// Binding the address-structure to the socket
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
printf("Error: bind() failed for port: %d \n", portStruct->portNumber);
//return 2;
}
// Geting sockfd
portStruct->sockfd = sockfd;
pthread_exit(0);
}
Problem is not clear what needs to be implemented. If various ports sockets have to accept, then it has to happen in thread function as well as recv call. In server function there are accept and recv calls which are blocking by default.
The main function should wait for connections. Upon receiving a request from the client, you create a thread that will handle this specific connection. So you will create the threads in the loop, meaning, you can theoretically have an infinite number of threads.
However, you can add a little logic to limit the number of threads that are existing at a particular time (thread pool).
So your main loop can look like this:
while (1) {
// accept: wait for a connection request
childfd = accept(parentfd, (struct sockaddr *) &clientaddr, (socklen_t *) &clientlen);
if (childfd < 0){
fprintf(stderr,"ERROR on accept");
continue;
}
hostaddrp = inet_ntoa(clientaddr.sin_addr);
if (hostaddrp == NULL){
fprintf(stderr,"ERROR on inet_ntoa\n");
continue;
}
fprintf(stdout,"server established connection with client\n");
pthread_t new_thread;
newSock = malloc(1);
*newSock = childfd;
if( pthread_create( &new_thread , NULL , server_thread , (void*) newSock) < 0){
bzero(logMsg, MAXSTRING);
sprintf(logMsg, "Thread for connection %d could not be created",childfd);
fprintf(stderr, "%s\n", logMsg);
continue;
}
fprintf(stdout, "thread created for connection %d\n", childfd);
}
The server_thread function could look like:
void *server_thread(void* clientSock){
int childfd = *(int*)clientSock;
char buf[MAXLINE]; // message buffer
int n; // message byte size
char logMsg[MAXSTRING];
size_t siz_failresp;
// read: read input string from the client
bzero(buf, MAXLINE);
n = (int) read(childfd, buf, MAXLINE);
if (n < 0){
sprintf(logMsg, "ERROR reading from socket");
fprintf(stderr,"%s", logMsg);
close(childfd);
fprintf(stdout, "Client %d disconnected \n=================\n", childfd);
//Free the socket pointer
free(clientSock);
return NULL;
}
// else, do processing of data received...
// ...................
}
There may be unused variables here above... I just got this code from one of my projects, just removing parts that do not concern you :-)
Hope it helps
End goal:
For the parent process of the server to know what clients join or leave the multicast group. So far I've only tried to check on clients joining, for I assume checking on those leaving is a similar matter.
My method(s) so far:
Checking for changes in the socket of the multicast group through select().
After joining, the client executes a sendto() directed to the (parent process of) the server program. The select() in the server is meant to recognize any changes, but apparently doesn't, and thus retval != 0 is never true.
Results so far
I Have tried with many different IP addresses and constants such as INADDR_ANY, but I've only managed as far as sending a message back to the client through the multicast, and this one interpret it as if the server-program had sent it. The most common result is the server-program not receiving any message at all.
Here is my client code:
/* Receiver/client multicast Datagram*/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_MSG 100
struct sockaddr_in localSock, servSock;
struct ip_mreq group;
int sd, n;
int datalen, mcastport;
char msg[MAX_MSG];
int main(int argc, char *argv[])
{
if(argc!=3) {
printf("usage : %s <address> <port>\n",argv[0]);
exit(0);
}
mcastport = atoi(argv[2]);
/* Create a datagram socket on which to receive. */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
perror("Opening datagram socket error");
exit(1);
}
else
printf("Opening datagram socket....OK.\n");
/* Enable SO_REUSEADDR to allow multiple instances of this */
/* application to receive copies of the multicast datagrams. */
{
int reuse = 1;
if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
perror("Setting SO_REUSEADDR error");
close(sd);
exit(1);
}
else
printf("Setting SO_REUSEADDR...OK.\n");
}
/* Bind to the proper port number with the IP address */
/* specified as INADDR_ANY. */
memset((char *) &localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(mcastport);
localSock.sin_addr.s_addr = INADDR_ANY;
if(bind(sd, (struct sockaddr*)&localSock, sizeof(localSock)))
{
perror("Binding datagram socket error");
close(sd);
exit(1);
}
else
printf("Binding datagram socket...OK.\n");
printf("Enter the group's name you want to join:\n");
scanf("%s", msg);
/* Join the multicast group 226.1.1.1 on the local IP address */
/* interface. Note that this IP_ADD_MEMBERSHIP option must be */
/* called for each local interface over which the multicast */
/* datagrams are to be received. */
group.imr_multiaddr.s_addr = inet_addr(argv[1]);
group.imr_interface.s_addr = inet_addr("127.0.0.1");
if(setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
{
perror("Adding multicast group error");
close(sd);
exit(1);
}
else
printf("Adding multicast group...OK.\n");
/* Initialize the group sockaddr structure with a */
/* group address of 226.1.1.1 and port given by user. */
memset((char *) &servSock, 0, sizeof(servSock));
servSock.sin_family = AF_INET;
servSock.sin_addr.s_addr = inet_addr(argv[1]);
servSock.sin_port = htons(mcastport);
if(sendto(sd, "", 1, 0, (struct sockaddr*) &servSock, sizeof(servSock)) < 0)
{perror("Sending datagram message error");}
else
printf("Sending datagram message...OK\n");
/* Read from the socket. */
if((n=read(sd, msg, MAX_MSG)) < 0)
{
perror("Reading datagram message error");
close(sd);
exit(1);
}
else
{
printf("Reading datagram message...OK.\n");
printf("The message from multicast server is: \"%s\"\n", msg);
}
msg[n] = '\0';
return 0;
}
This is my server program code:
/* Send Multicast Datagram code*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h> /* for strncpy, memset */
#define MAX_MSG 100
struct in_addr localInterface;
struct sockaddr_in groupSock, cliAddr;
int sd, mcastport, maxJoin, maxJoined = 0, pipefd[2], cliLen, cpid;
char msg[MAX_MSG], groupName[MAX_MSG];
int main (int argc, char *argv[ ])
{
/* check command line args */
if(argc < 2) {
printf("usage : %s <port> \n", argv[0]);
exit(1);
}
mcastport = atoi(argv[1]);
/* Create a datagram socket on which to send. */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
perror("Opening datagram socket error");
exit(1);
}
else
printf("Opening the datagram socket...OK\n");
/* Initialize the group sockaddr structure with a */
/* group address of 225.1.1.1 and port given by user. */
memset((char *) &groupSock, 0, sizeof(groupSock));
groupSock.sin_family = AF_INET;
groupSock.sin_addr.s_addr = inet_addr("226.1.1.1");
groupSock.sin_port = htons(mcastport);
printf("Create a group: ");
scanf("%s", groupName);
printf("Maximum number of clients that can join the group? ");
scanf("%d", &maxJoin);
/* Disable loopback so you do not receive your own datagrams.
{
char loopch = 0;
if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopch, sizeof(loopch)) < 0)
{
perror("Setting IP_MULTICAST_LOOP error");
close(sd);
exit(1);
}
else
printf("Disabling the loopback...OK.\n");
}
*/
/* Set local interface for outbound multicast datagrams. */
/* The IP address specified must be associated with a local, */
/* multicast capable interface. */
printf("Setting the local interface...");
localInterface.s_addr = inet_addr("127.0.0.1");
if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localInterface, sizeof(localInterface)) < 0)
{
perror("error");
exit(1);
}
else
printf("OK\n");
if((cpid = fork()) == 0) //child process --sends messages
{
/* Send a message to the multicast group specified by the*/
/* groupSock sockaddr structure. */
printf("Enter a message to send: \n");
scanf("%s", msg);
if(sendto(sd, msg, strlen(msg)+1, 0, (struct sockaddr*)&groupSock, sizeof(groupSock)) < 0)
{perror("Sending datagram message error");}
else
printf("Sending datagram message...OK\n");
/* Try the re-read from the socket if the loopback is not disable
if(read(sd, databuf, datalen) < 0)
{
perror("Reading datagram message error\n");
close(sd);
exit(1);
}
else
{
printf("Reading datagram message from client...OK\n");
printf("The message is: %s\n", databuf);
}
*/
exit(EXIT_SUCCESS);
}
else //parent process --checks for JOINs and QUITs
{
fd_set rfds;
struct timeval tv;
int retval, status;
while (waitpid(cpid, &status, WNOHANG) != cpid)
{
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(sd, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select(sd+1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
else if (retval != 0)
{
printf("Data is available now.\n");
/* FD_ISSET(0, &rfds) will be true. */
cliLen = sizeof(cliAddr);
int n;
if((n = recvfrom(sd, msg, MAX_MSG, 0, (struct sockaddr *) &cliAddr,&cliLen)) == -1)
perror("Some bullshit happened");
msg[n] = '\0';
printf("Client IP:port is: %s:%d", inet_ntoa(cliAddr.sin_addr), (int) ntohs(cliAddr.sin_port));
} else
{printf("no data.\n");}
}
exit(0);
}
return 0;
}
Possible solutions I haven't tried:
Maybe I shouldn't use the multicast group to send information client->server, but rather another type of connection? I'm just guessing here. I know you guys don't like doing anyone's work.
I have been at this "simple" issue for several hours and tried reading everywhere I could, including this question which seems very similar, but I haven't managed to solve it in any way. I'm completely striking out here.
If the client sends to the multicast group and the server expects to read that, the server needs to join the multicast group as well.
It isn't a great solution, as all the other client members will also receive that multicast.
It would make more sense for the client to first receive a multicast from the server, and then to respond to the server's address, which is provided via the result arguments of recvfrom().
Two points that may help you:
There is no need to use multicasting if your communication is only local (you use 127.0.0.1 in your code)
Multicast groups are joined by network interfaces, not by processes. Once a network interface has joined a multicast interface, a second joining of the same network interface to the same multicast group will change nothing. Even when it's another process on the same host that requests the second
joining.
I'm writing simple TCP server and I found some issue. Maybe you can help me a bit.
So, I wrote an echo server first (to test connection with computer client). It's working okay, but now I need to change it a bit. Server should sent char[100] to client when it connects and sent same char[] to every client every X seconds/minutes.
I've trying many changes, but application only crashes. Commented some of my "mistakes" in this code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
/* BufferLength is 100 bytes */
#define BufferLength 100
/* Server port */
#define SERVPORT 6000
int main(){
/* Variable and structure definitions. */
int sd, wyslij, sd2, rc, length = sizeof(int);
int totalcnt = 0, on = 1;
char temp;
char buffer[BufferLength];
struct sockaddr_in serveraddr;
struct sockaddr_in their_addr;
fd_set read_fd;
struct timeval timeout;
timeout.tv_sec = 15;
timeout.tv_usec = 0;
char datadata[100] = "This is a test string from server lol!!! ";
/* Get a socket descriptor */
if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
perror("Server-socket() error");
/* exit */
exit (-1);
}else
printf("Server-socket() is OK\n");
/* Allow socket descriptor to be reusable */
if((rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) < 0){
perror("Server-setsockopt() error");
close(sd);
exit (-1);
}else
printf("Server-setsockopt() is OK\n");
/* bind to an address */
memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVPORT);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
printf("Using %s, listening at %d\n", inet_ntoa(serveraddr.sin_addr), SERVPORT);
if((rc = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0){
perror("Server-bind() error");
/* Close the socket descriptor */
close(sd);
/* and just exit */
exit(-1);
}else
printf("Server-bind() is OK\n");
/* queue up to 10 clients */
if((rc = listen(sd, 10)) < 0){
perror("Server-listen() error");
close(sd);
exit (-1);
}else
printf("Server-Ready for client connection...\n");
/* accept() the incoming connection request. */
int sin_size = sizeof(struct sockaddr_in);
if((sd2 = accept(sd, (struct sockaddr *)&their_addr, &sin_size)) < 0){
perror("Server-accept() error");
close(sd);
exit (-1);
}else
printf("Server-accept() is OK\n");
/*client IP*/
printf("Server-new socket, sd2 is OK...\n");
printf("Got connection from the client: %s\n", inet_ntoa(their_addr.sin_addr));
/* Wait for up to 15 seconds on */
/* select() for data to be read. */
FD_ZERO(&read_fd);
FD_SET(sd2, &read_fd);
rc = select(sd2+1, &read_fd, NULL, NULL, &timeout);
/* rc = write(sd2, datadata, sizeof(datadata)); */
if((rc == 1) && (FD_ISSET(sd2, &read_fd))){
/* rc = write(sd2, datadata, sizeof(datadata)); */
/* Read data from the client. */
totalcnt = 0;
while(totalcnt < BufferLength){
/* read() from client */
rc = read(sd2, &buffer[totalcnt], (BufferLength - totalcnt));
if(rc < 0){
perror("Server-read() error");
close(sd);
close(sd2);
exit (-1);
}else if (rc == 0){
printf("Client program has issued a close()\n");
close(sd);
close(sd2);
exit(-1);
}
else{
totalcnt += rc;
printf("Server-read() is OK\n");
}
}
}else if (rc < 0){
perror("Server-select() error");
close(sd);
close(sd2);
exit(-1);
}
/* rc == 0 */
else{
printf("Server-select() timed out.\n");
close(sd);
close(sd2);
exit(-1);
}
/* Shows the data */
printf("Received data from the client: %s\n", buffer);
/* write() some bytes of string, */
/* back to the client. */
printf("Server-Echoing back to client...\n");
rc = write(sd2, datadata, sizeof(datadata));
if(rc != totalcnt){
perror("Server-write() error");
/* Get the error number. */
rc = getsockopt(sd2, SOL_SOCKET, SO_ERROR, &temp, &length);
if(rc == 0){
/* Print out the asynchronously */
/* received error. */
errno = temp;
perror("SO_ERROR was: ");
}else
printf("Server-write() is OK\n");
close(sd);
close(sd2);
exit(-1);
}
/* Close the connection to the client and */
/* close the server listening socket. */
close(sd2);
close(sd);
exit(0);
return 0;
}
Thanks a lot buddies!
You may want to check out D.J. Bernstein's tcpserver (see http://cr.yp.to/ucspi-tcp/tcpserver.html). Basically, you can simply run your C program under tcpserver, and tcpserver will handle everything as far as setting up the sockets, listing for incoming connections on whatever port you are using, etc. When an incoming connection arrives on the port that you specify, tcpserver will spawn an instance of your program and pipe incoming info from the client to your program's STDIN, and pipe outgoing info from your program's STDOUT back to the client. This way, you can concentrate on your program's core logic (and simply read/write to stdout/stdin), and let tcpserver handle all of the heavy lifting as far as the sockets, etc.
Well, I ran your program against a simple TCP client code and did not see any crash. So, you probably should add gdb info to that. Also, in the program, I don't see where your programs wakes up periodically (you do have a comment) and sends data to the client. You should also consider adding the client fd to the list of read fd set and have one common select() call. If the select() returns a read-event on the listener, then that is a new connection and you should call accept. If the select() returns a read-event on a child fd, then you have some data to read adn you should call recv()/read().
On every new client connection forked server process
different processes(other children of server i.e. exec) couldn't identify that client with same fd in used in forked child.
How can I differentiate client on other processes ??
accept call is returning same value if file descriptor new sockfd
/* server process */
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#define SIZE sizeof(struct sockaddr_in)
void catcher(int sig);
int newsockfd;
int main(void)
{
int sockfd;
char c;
struct sockaddr_in server = {AF_INET, 7000, INADDR_ANY};
static struct sigaction act;
act.sa_handler = catcher;
sigfillset(&(act.sa_mask));
sigaction(SIGPIPE, &act, NULL);
/* set up the transport end point */
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket call failed");
exit(1);
}
/* bind an address to the end point */
if ( bind(sockfd, (struct sockaddr *)&server, SIZE) == -1)
{
perror("bind call failed");
exit(1);
}
/* start listening for incoming connections */
if ( listen(sockfd, 5) == -1 )
{
perror("listen call failed");
exit(1) ;
}
for (;;)
{
/* accept a connection */
if ( (newsockfd = accept(sockfd, NULL, NULL)) == -1)
{
perror("accept call failed");
continue;
}
printf("New connection. File descriptor fd is %d\n",newsockfd);
/* spawn a child to deal with the connection */
if ( fork() == 0)
{
while (recv(newsockfd, &c, 1, 0) > 0)
{
c = toupper(c);
send(newsockfd, &c,1, 0);
}
/* when client is no longer sending information the socket can be closed and the child process terminated */
close(newsockfd);
exit (0);
}
/* parent doesn't need the newsockfd */
close(newsockfd);
}
}
void catcher(int sig)
{
close(newsockfd);
exit (0);
}
/* client process */
#include <ctype.h>
#include <sys/types.h>
#include<stdlib.h>
#include<stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SIZE sizeof(struct sockaddr_in)
int main(void)
{
int sockfd;
char c, rc;
struct sockaddr_in server = {AF_INET, 7000};
/* convert and store the server's IP address */
server.sin_addr.s_addr = inet_addr("127.0.0.1");
/* set up the transport end point */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket call failed");
exit(1);
}
/* connect the socket to the server's address */
if ( connect (sockfd, (struct sockaddr *)&server, SIZE) == -1)
{
perror("connect call failed");
exit(1);
}
/* send and receive information with the server */
for(rc = '\n';;)
{
if (rc == '\n')
printf("Input a lower case character\n");
c = getchar();
send(sockfd, &c, 1, 0);
if (recv(sockfd, &rc, 1, 0) >0)
printf("%c", rc);
else
{
printf("server has died\n");
close(sockfd);
exit(1);
}
}
}
The file descriptor number is unique only within the process it exists in, and as soon as it's closed, it can be reused (for example the next time you call accept). It is not a good choice of "connection identifier".
In your case where you have a new process for each connection, the most natural identifier for a connection would be the process id - but you've thrown it away by not saving the return value of fork. In the parent process, fork returns the pid of the child process it created. You want to save this and use it later. In particular you can use it to kill the child process or identify when the child process exits (wait-family functions will tell you which child exited).
Of course if your whole model is to use a separate process for each connection, I'm not sure why you need to identify connections at all in the parent process. If each connection is not a completely independent process, you might do a lot better using threads instead of processes.