I have the following code serving as main loop for a server that accepts incoming socket connections.
At the moment the macro OperationMode is defined as 1 so it will execute the pthread logic.
for (hit = 1 ;; hit++) {
printf("Got here\n\n");
length = sizeof(cli_addr);
/* block waiting for clients */
socketfd = accept(listenfd, (struct sockaddr *) &cli_addr, &length);
if (socketfd < 0)
printf("ERROR system call - accept error\n");
else
{
printf("Testing\n\n\n");
#ifdef OperationMode
pthread_t thread_id;
if(pthread_create(&thread_id, NULL, attendFTP(socketfd, hit), NULL))
{
perror("could not create thread");
return 1;
}
#else
pid = fork();
if(pid==0)
{
ftp(socketfd, hit);
}
else
{
close(socketfd);
kill(pid, SIGCHLD);
}
#endif
}
}
I'm able to create a thread for the first incoming socket connection but once I iterate over the loop I get segmentation fault error in the line
socketfd = accept(listened, (struct sockaddr *) &cli_addr, &length);
My attendFTP function has the following code
void *attendFTP(int fd, int hit)
{
ftp(fd, hit);
return NULL;
}
This works perfect for the fork implementation. How can I fix the segmentation fault error?
pthread_create(&thread_id, NULL, attendFTP(socketfd, hit), NULL);
This code passess result of a call to attendFTP() with given paramters - and this result is always NULL.
So pthread_create is trying to launch a function at NULL address and, correspondingly, fails.
If you run your compiler with -pedantic argument, compiler will tell you that what you are doing is wrong. Without -pedantic, gcc allows for some 'extensions', which might hide errors. Btw, this is why -pedantic is, in my view, a must.
What you actually want is to pass some arguments to your threading function. Unfortunately, it is really convoluted in C pthreads, and requires you to allocate and deallocate the said struct. Something like this:
struct args {
int fd;
int hit;
};
...
pthread_t thread_id;
struct args* args = malloc(sizeof(struct args));
args->fd = socketfd;
args->hit = hit;
if(pthread_create(&thread_id, NULL, attendFTP, args))
....
void* attendFTP(void* vargs)
{
struct args* args = vargs;
ftp(args->fd, args->hit);
free(args);
return NULL;
}
Related
I am practicing different forms of causing a server to run concurrently by being able to accept multiple responses from multiple clients. This is a school assignment.
I am now having troubles with threading. The thread works but gets an error of
"curl: (56) Recv failure: Connection reset by peer"
This is because of the line in the response function that my thread goes to. Rest assured all variables besides clients[n] are pretty much constants. So its rather not passing in right or I'm completely missing the mark on how threading should be done.
rcvd = recv(clients[n], mesg, 99999, 0);
which this line keeps returning -1 into rcvd and I want > 0.
Here is my code.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<signal.h>
#include<fcntl.h>
#include<pthread.h>
#include "functions.h"
#define CONNMAX 1000
#define BYTES 1024
char *ROOT;
int verbose;
int signalReceived = 1;
int listenfd, clients[CONNMAX], slot;
pthread_t thread;
void error(char *);
void *threadServer(void *arg)
{
printf("bong");
respond(slot, verbose, ROOT, clients);
exit(0);
}
void clean(int arg)
{
signalReceived = 0;
}
int main(int argc, char *argv[])
{
signal(SIGINT, clean);
signal(SIGHUP, clean);
struct sockaddr_in clientaddr;
socklen_t addrlen;
char c;
char PORT[6];
ROOT = getenv("PWD");
strcpy(PORT, "8888");
while ((c = getopt (argc, argv, "p:v")) != -1)
switch (c)
{
case'v':
verbose = 1;
break;
case'p':
strcpy(PORT, optarg);
break;
case'?':
fprintf(stderr, "Wrong arguments given\n");
exit(1);
default:
exit(1);
}
printf("Listening on port %s%s%s, root is %s%s%s\n", "\033[92m", PORT, "\033[0m", "\033[92m", ROOT, "\033[0m");
int i = 0;
for (i = 0; i < CONNMAX; i++)
clients[i] = -1;
startServer(PORT, &listenfd);
while (signalReceived == 1)
{
addrlen = sizeof(clientaddr);
clients[slot] = accept (listenfd, (struct sockaddr *) &clientaddr, &addrlen);
if (clients[slot] < 0)
exit(0);
else
{
printf("bang");
pthread_create(&thread, NULL, threadServer, NULL);
}
while (clients[slot] != -1)
slot = (slot + 1) % CONNMAX;
}
return 0;
}
I am learning and this is not my original source work, rather an edited work in order to learn. I took a forked original program and am now trying to convert it to a threaded program.
slot is a global variable. Starting a thread can take a little while, and threads share the same memory. They don't have their own snapshots of it like a forked process does.
After starting the thread, your main process alters slot.
Best case scenario: new thread starts and gets the new value of slot such that connections[slot] == -1. Worst case: the thread runs on a different CPU core and gets slot while main is writing to it, resulting in a bad value.
You might want to consider passing slot as a parameter to the thread function instead:
void *threadServer(void *arg)
{
int mySlot = (int)arg;
printf("bong\n");
respond(mySlot, verbose, ROOT, clients);
clients[mySlot] = -1;
printf("bash\n");
return NULL; // calling 'exit' terminates the whole process. duh.
}
// ...
pthread_create(&thread, NULL, threadServer, (void*)slot);
Another issue you have here is that you create all these threads but you do not keep track of them individually. You probably need an array of threads, or you might want to consider a simple struct:
typedef struct Clients {
int fd;
pthread_t thread;
} Clients;
Clients clients[MAXCONN];
//
while (signalReceived == 1)
{
addrlen = sizeof(clientaddr);
clients[slot].fd = accept(listenfd, (struct sockaddr *) &clientaddr, &addrlen);
if (clients[slot].fd < 0)
exit(0);
else
{
printf("bang");
pthread_create(&clients[slot].thread, NULL, threadServer, (void*)slot);
}
while (clients[slot] != -1)
slot = (slot + 1) % CONNMAX; // what if we can't find one?
}
Your threadServer function calls exit, terminating the process.
I'm not sure where that came from, since it wouldn't be appropriate in a server that calls fork either. But it's definitely fatal in a multi-threaded program.
Here is the threaded-server code in C. My question is: do we need to set unused thread to NULL? In java, we need to set thread to NULL to let it return to thread pool.
I made the change to Martin Broadhurst's source code (see gray text as comment)
/*
* A threaded server
* by Martin Broadhurst (www.martinbroadhurst.com)
* Compile with -pthread
*/
#include <stdio.h>
#include <string.h> /* memset() */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <pthread.h>
#define PORT "32001" /* Port to listen on */
#define BACKLOG 10 /* Passed to listen() */
void *handle(void *pnewsock)
{
/* send(), recv(), close() */
return NULL;
}
int main(void)
{
int sock;
pthread_t thread;
struct addrinfo hints, *res;
int reuseaddr = 1; /* True */
/* Get the address info */
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(NULL, PORT, &hints, &res) != 0) {
perror("getaddrinfo");
return 1;
}
/* Create the socket */
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock == -1) {
perror("socket");
return 1;
}
/* Enable the socket to reuse the address */
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1) {
perror("setsockopt");
return 1;
}
/* Bind to the address */
if (bind(sock, res->ai_addr, res->ai_addrlen) == -1) {
perror("bind");
return 0;
}
freeaddrinfo(res);
/* Listen */
if (listen(sock, BACKLOG) == -1) {
perror("listen");
return 0;
}
/* Main loop */
while (1) {
pthread_attr_t *attr; //<===I added this
size_t size = sizeof(struct sockaddr_in);
struct sockaddr_in their_addr;
int * ptr; //<===I added this
ptr = malloc(sizeof(int)); //<===I added this
ptr = accept(sock, (struct sockaddr*)&their_addr, &size);
if (newsock == -1) {
perror("accept");
}
else {
printf("Got a connection from %s on port %d\n",
inet_ntoa(their_addr.sin_addr), htons(their_addr.sin_port));
//I added the following "if" statement
if (pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED) != 0){
fprintf(stderr, "Failed to set thread detached\n");
}
else {
//if (pthread_create(&thread, NULL, handle, &newsock) != 0) {
if (pthread_create(&thread, attr, handle, ptr) != 0 ) {
fprintf(stderr, "Failed to create thread\n");
}
}
}
}
close(sock);
return 0;
}
==========-==============
code is from here:
http://martinbroadhurst.com/source/threaded-server.c.html
No. Well, it's not 100% clear what Java construct it is you're thinking of (I bet there's a close method you can call instead of setting it to null and having the GC take care of it), but that's irrelevant because...
pthread_t is an integer (maybe) type, not a pointer, so it can't be set to NULL.
C is not garbage collected, so even if it were a pointer the thread would have no way of knowing or caring that you set it to null.
POSIX threads does not use a thread pool. The pthread_create function actually creates a brand-new OS-level thread, and returning from the handler actually exits it. (Well, not really. It still hangs around until you call pthread_join, since you didn't create it as a detached thread.)
What you should do is create the threads as detached threads, since your code right now is leaking joinable threads.
Also, using &newsock as the argument is dangerous, since it gets destroyed and recreated in every iteration of the main loop. This is a race condition that probably never showed up in the author's testing because under light load the main thread would be waiting for the next accept to return while it is accessed on the worker thread, and on most systems the same space will be used over and over for the variable.
You can use malloc to create a place to store the socket fd in (which you will need to free at the end of your handler function), or, if your platform allows this (most do), just cast the value to a pointer then cast it back out in the handler function.
Since C doesn't have objects, there is no object that represents the thread and so nothing to set to NULL. A detached thread will go away when it terminates. An undetached thread will go away when it's joined.
You have a pthread_t as thread id, there is no object, and it don't work in the way as java gc.
Thread terminate in 1 of following cases:
its start function return,
the thread call pthread_exit()
canceled by pthread_cancel()
any of threads in the process call exit(),
the main thread returns,
in this case, all threads in the process will terminate immediately,
I'm having a segmentation fault problem with a networking program using threads to deal with each new connection.
MAX_PEERS is defined above as 10.
...
int iret[MAX_PEERS];
pthread_t thread[MAX_PEERS];
(void) signal(SIGCHLD, reaper);
printf("before while\n");
int i = 0;
while(1) {
if(i>MAX_PEERS-1){break;}
client_len = sizeof(client);
new_sd = accept(sd, (struct sockaddr *)&client, &client_len);
if(new_sd < 0){
fprintf(stderr, "Can't accept client \n");
exit(1);
}
printf("before thread\n");
iret[i] = pthread_create(&thread[i], NULL, connection, (void*) new_sd);
if(iret != 0){
printf("thread[%d] not generated!\n", i);
}
i++;
printf("end of while\n");
}
....
and the function "connection" beggins as follows
void *connection(void *sdd)
{
int sd =* (int *) sdd;
...
When the client tries to connect to the server I get a segmentation fault.
> ./server 20011
before while
before accept
after accept
before thread
./server: zsh: segmentation fault ./server 20011
>
It prints "before accept" before the client connects, and after the client connects it prints the rest.
Am I creating the threads correctly? Any ideas?
Thanks,
accept() returns an integer, so new_sd must be an integer. When you create a new thread you cast new_sd to a void pointer. But when you get that pointer in the function, instead of casting back to int you cast it to a pointer to int and dereference it, which causes the seg fault.
Instead of using possibly incorrect casting, rather pass an integer. Assuming that new_sd will go out of scope, allocate space for an integer and pass it to your thread.
int* new_sdp = malloc( sizeof( *new_sdp )) ;
*new_sdp = new_sd ;
iret[i] = pthread_create(&thread[i], NULL, connection, new_sdp);
and in the thread:
void *connection(void *sdd)
{
int sd = *(int *)sdd;
this is a simple program I've been working on that listens to a socket, and starts a new thread to handle each connection to said socket.
In my while loop I get a Segmentation Fault, that has something to do with pthread_create (if I comment that line out the program loops properly). My knowledge of pointers is mediocre at best, and debugging with gdb didn't yield anything of value. This is gdb's output:
#0 0x0000000000000000 in ?? ()
#1 0x000000080064f4f1 in pthread_getprio () from /lib/libthr.so.3
#2 0x0000000000000000 in ?? ()
Error accessing memory address 0x7fffffbff000: Bad address.
The program gets through the while loop once successfully, and properly receives and responds to a connection at the socket, but then before getting into the second while loop, the program fails on a Segmentation Fault error.
Here's a condensed version of my program:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <pthread.h>
#define UNIX_PATH_MAX 100
#define SOCK_PATH "/tmp/demo_socket"
/*===============> CONNECTION HANDLER FUNCTION <=================*/
void *connection_handler(int connection_fd)
{
int nbytes;
char buffer[256];
nbytes = read(connection_fd, buffer, 256);
buffer[nbytes] = 0;
printf("\tMESSAGE FROM CLIENT: %s\n", buffer);
nbytes = snprintf(buffer, 256, "Hello from the server!");
write(connection_fd, buffer, nbytes);
close(connection_fd);
return;
}
/*==========================> MAIN <=============================*/
int main(void)
{
struct sockaddr_un addr; //socket address information
int sock_fd, conn_fd; //socket file descriptors
socklen_t addr_len = sizeof(struct sockaddr_un); //size of sockaddr_un structure
pid_t child_pid; //pid holder
pthread_t thread; // thread identifier
sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock_fd < 0)
return 1;
unlink(SOCK_PATH);
memset(&addr, 0, addr_len);
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path) - 1); // Copies up to sizeof(addr.sun_path)-1 bytes from SOCK_PATH into addr.sun_path
printf("> Socket sun_family = %d (AF_UNIX), Socket sun_path = %s ...\n", addr.sun_family, addr.sun_path);
/*----------------------FAIL CHECKS-------------------------*/
if (bind(sock_fd, (struct sockaddr *) &addr, addr_len) != 0)
return 1;
if (listen(sock_fd, 5) != 0)
return 1;
printf("> Listening to socket bound at %s ...\n\n", SOCK_PATH);
/*--------------------WHILE LOOP----------------------------*/
while ( (conn_fd = accept(sock_fd, (struct sockaddr *) &addr, &addr_len)) > -1) {
pthread_create(&thread , NULL, connection_handler(conn_fd), NULL);
printf("> Closing connection at %d inside server process ...\n", conn_fd);
close(conn_fd);
printf("> Reached bottom of loop!\n");
}
/*---------------------------FIN------------------------------*/
close(sock_fd);
unlink(SOCK_PATH);
printf("> Socket closed and unlinked from path ... Done!\n ");
return 0;
}
Any help would be greatly appreciated!
This is wrong:
pthread_create(&thread , NULL, connection_handler(conn_fd), NULL);
pthread_create requires the address of the function to run in the new thread. What your code does is call connection_handler in the main thread and then pass the result of connection_handler to pthread_create as the function address.
What you need is the following:
pthread_create(&thread , NULL, connection_handler, (void*)conn_fd);
You'll also need to change connection_handler to take void* instead of int:
void *connection_handler(void* arg)
{
intptr_t connection_fd = (intptr_t)arg;
...
}
Your usage of pthread_create is incorrect. the third argument should be a pointer to a function of type void *(*start_routine) (void *), instead you are passing the return of connection_handler.
Change connection_handler to receive a void * argument (and make sure it returns an actual value), eg.
#include <stdint.h>
void *connection_handler(void *arg)
{
intptr_t connection_fd = (intptr_t)arg;
...
return NULL;
}
and change your call to something like the following
pthread_create(&thread, NULL, &connection_handler, (void *)conn_fd);
You should also make sure to either start the thread detached, detach the thread with pthread_detach or join it later with pthread_join
buffer[nbytes] = 0;
This will overflow if you've read 256 bytes. Increase buffer size or decrease read size by one.
Most likely because you are closing the socket connection in two places. There is good chance that in one run of the thread its not yet got around to the write but in your parent thread already closed the connection.
Why do you need to create so many threads? Wouldn't one worker thread suffice? you can pile up the jobs on to this worker thread...
I have two nodes communicating with a socket. Each node has a read thread and a write thread to communicate with the other. Given below is the code for the read thread. The communication works fine between the two nodes with that code. But I am trying to add a select function in this thread and that is giving me problems (the code for select is in the comments. I just uncomment it to add the functionality). The problem is one node does not receive messages and only does the timeout. The other node gets the messages from the other node but never timesout. That problem is not there (both nodes send and receive messages) without the select (keeping the comments /* */).
Can anyone point out what the problem might be? Thanks.
void *Read_Thread(void *arg_passed)
{
int numbytes;
unsigned char *buf;
buf = (unsigned char *)malloc(MAXDATASIZE);
/*
fd_set master;
int fdmax;
FD_ZERO(&master);
*/
struct RWThread_args_template *my_args = (struct RWThread_args_template *)arg_passed;
/*
FD_SET(my_args->new_fd, &master);
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
int s_rv = 0;
fdmax = my_args->new_fd;
*/
while(1)
{
/*
s_rv = -1;
if((s_rv = select(fdmax+1, &master, NULL, NULL, &tv)) == -1)
{
perror("select");
exit(1);
}
if(s_rv == 0)
{
printf("Read: Timed out\n");
continue;
}
else
{
printf("Read: Received msg\n");
}
*/
if( (numbytes = recv(my_args->new_fd, buf, MAXDATASIZE-1, 0)) == -1 )
{
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
printf("Read: received '%s'\n", buf);
}
pthread_exit(NULL);
}
You must set up master and tv before each call to select(), within the loop. They are both modified by the select() call.
In particular, if select() returned 0, then master will now be empty.