I am new to both sockets and threads. I have this code:
listen(socket_fd, 20);
/* Looooop */
while (1) {
newsocket_fd = accept(socket_fd,
(struct sockaddr *) &client_addr,
&client_len);
if (newsocket_fd < 0) {
error("ERROR on accept");
}
pthread_t thread;
pthread_create(&thread, NULL, run_thread, (void *) newsocket_fd);
pthread_join(thread, NULL);
}
How can I start a new thread for each new connection, rather than for each request? These threads should be started when a new connection comes in, and these threads should then wait for requests, handle those requests, and finally return when the connection is closed. There should be one thread for each connection. Here is the code for run_thread:
void
*run_thread(void *ptr) {
char buffer[256];
bzero(buffer, 256);
int n;
n = read((int) ptr, buffer, 255);
if (n < 0) error("ERROR Reading from socket");
printf("%s\n\n**********\n\n", buffer);
/* Parse buffer and return result */
char *result;
{
/* First, determine command, 4 characters */
/* (much code) */
}
n = write((int) ptr, result, strlen(result));
if (n < 0) error("ERROR Writing to socket");
}
Can anyone help me? Thanks.
There is also a different critical error.
You cast the int to (void*). This does not make sense. Also, you can't pass the address directly since the variable could be changed on the next accept() call before the thread can copy the variable to its local stack. One way to write it would be something like this:
while (1) {
newsocket_fd = accept(socket_fd,
(struct sockaddr *) &client_addr,
&client_len);
if (newsocket_fd < 0) {
error("ERROR on accept");
}
pthread_t thread;
int *newsock = malloc(sizeof(int));
*newsock = newsocket_fd;
pthread_create(&thread, NULL, run_thread, newsock);
pthread_detach(thread);
}
With this approach, the thread will make sure to free() the newsock. E.g a simple
void *handler(void *thread_data) {
int fd = *(int *) thread_data;
free(thread_data);
....
}
Also, I assume pthread_detach() is okay, if the main program doesn't care about syncing up with the thread later with pthread_join().
You almost got it right. The problem is, however, that you are joining the thread right after creation, and pthread_join is actually a blocking call which is waiting for the thread to finish. It means that you will not be able to accept any more connections while that one thread is running. To solve this problem, you might want to use detached threads. You don't have to join detached threads. For this purpose, you have to create thread attributes using pthread_attr_init function and pass those attributes to pthread_create.
Be aware that if you have too many client connections, your application may run out of resources. So, in real world, you have to manage a pool of threads. But the best case scenario for TCP/IP server applications is to use asynchronous I/O. I do not know about C, but there is a very good library in C++ for asynchronous I/O application called boost::asio.
Vlad has good advice.
Also note that your newsocket_fd variable is being reused for each new connection in your accept loop, and then a pointer to it is passed to every worker thread. This will cause problems when you start having multiple clients connected at the same time.
EDIT: Ignore this comment, I misread the mistake you were making. Others have given proper corrections for your handling of newsocket_fd.
Related
I have a server that accepts clients. I'm doing some multi-threading, and when I create a thread, I pass the socketfd as an argument. The accept fails because the sockFd it takes is zero. However I can't figure out why this would be the case. The sockfd is valid for the take_client function, and it has been set up correctly. I just included this section of my code because I'm certain the issue is here.
void* thread_func(void* pSockfd) {
int sockFd;
sockFd = *(int*)pSockfd;
printf("sockFD = %d\n", sockFd); //returns zero
struct sockaddr_in sockAddr;
socklen_t sockAddrSize;
sockAddrSize = sizeof(struct sockaddr_in);
accept(sockFd, (struct sockaddr*) &sockAddr, &sockAddrSize);
return 0;
}
void take_client(int sock) { //when called, 'sock' is a valid number > 0
pthread_t thread_id;
pthread_create(&thread_id, NULL, thread_func, (void*)&sock);
}
If anything stands out that might be an issue, I'd be really grateful to hear. Thanks!
there is a race condition in you code, it may look ok "sometimes":
void take_client(int sock) { //sock live on stack here
pthread_t thread_id;
pthread_create(&thread_id, NULL, thread_func, (void*)&sock);
// you pass the stack address of sock to your thread
}
The address you pass must remain valid when thread is running, thus either you can afford that(it is kind of "global" somewhere), either you need to allocate a new buffer and pass it to the thread.
Sometime you will see code casting sock value to void* ( (void*)sock) and casting back the pointer to an int in the thread.
This may work, but I think allocating a new buffer is better for readability, and gives a clear ownership of who is responsible for this buffer (having a shared 'sock' between threads would need locking to be perfectly safe).
Moreover, usually, you end up with the need of passing many more info to the thread, thus already having a buffer ease the evolution of your code.
check out the man page for socket return value: "On success, a file descriptor for the new socket is returned. On error, -1 is returned, and errno is set appropriately." So a zero return value is valid. unless I didn't understand the issue you have.
I have C linux TCP Client/Server application.
I came up with a strange scenario, but I don't know if there are any consequences with this application.
I have a server side that can accept N connections, for example this server will accept 100 connections.
In this scenario I create the listen socket in the main thread, then I create 100 threads and each thread has an independent accept() and a select() iomux, also each thread can only accept one connection.
My concerns here, if two simultaneous accept() want to accept the same socket(connection) because of the select is a ready to read on the same socket, I don't know if the simultaneous accepts are thread safe in kernel and only one accept can handle that incoming connection and the other will wait for another connection?
I tried that on my RedHat machine that works fine, but I don't know If I am a lucky enough to avoid a deadlock!
Thanks
rc = bind(sd, (struct sockaddr_in *)& groupSock, sizeof(struct sockaddr_in));
CHECK_VALUE("Bind address error", rc, 0, goto cleanup);
rc = listen(sd, 10);
CHECK_VALUE("listen", rc, 0, goto cleanup);
for(; count< num_socks; count++){
par_data[count].sd = sd;
par_data[count].thread_num = count;
par_data[count].err_chk = -1;
rc = pthread_create(&thread_id[count], NULL, accept_sock_thread, (void *)& par_data[count]);
CHECK_VALUE("pthread_create", rc, 0, goto cleanup);
}
void * accept_sock_thread(void* atr){
int rc;
int sock = INVALID_SOCKET;
int datalen = config.traffic;
char *databuf = NULL;
struct thread_data *data = NULL;
struct sockaddr_in tcp_remote;
struct timeval t;
socklen_t size;
fd_set socks;
databuf = malloc(sizeof(char) * datalen);
memset(databuf, 0, datalen);
data = (struct thread_data*) atr;
DEBUG(my_debug_flags, ENTER_FUNCT, ("Enter Function accept_sock_thread thread_num %d \n", data->thread_num));
FD_ZERO(&socks);
FD_SET(data->sd, &socks);
t.tv_sec = 25;
t.tv_usec = 0;
rc = select(data->sd + 1 , &socks, NULL, NULL,&t);
if(rc < 0){
VL_MISC_ERR(("Error in select with Errno: %d", errno));
goto cleanup;
}
else if(rc == 0){
VL_MISC_ERR(("Accept Select returned a TIEMOUT."));
goto cleanup;
}
size = sizeof(struct sockaddr_in);
sock = accept(data->sd, (struct sockaddr *)& tcp_remote, &size);
CHECK_NOT_EQUAL("tcp accept error", sock, INVALID_SOCKET, goto cleanup);
cleanup:
// sleep(2); /* avoid EOF */
if(sock != INVALID_SOCKET){
rc = close(sock);
if(rc != 0){
data->err_chk = -1;
}
}
return NULL;
}
accept() is thread-safe and reentrant according to POSIX.
This means that two call of accept on the same descriptor should not give an undefined behaviour. One of the accept will open the socket and the other will return an error.
You can see a little more there :
Is accept() thread-safe?
Are BSD/Posix sockets reentrant?
Only one thread is going to accept the connection. The kernel insures this. It has been this way in the unix/posix world for a very long time now.
Only one thread would accept(), so far so good ... - but before this all threads will be triggered to have select() return, which might not be what you want.
So if you'd had N threads sleeping in select() and one connection comes in all threads would wake up, but only one would be needed, as only one would succeed in accept()ing.
To use accept() on same socket object from multiple threads/processes is not only standard, but also widly used strategy. From my knowledge apache does this. nginx does this too but in slightly different fashion.
Do note: select() can wake up multiple threads, but only one of them will accept connection, while others will either a) hang in accept() or b) return -1 and set errno to EAGAIN in case of non-blocking IO. Since you are using select() before accept() I suppose socket descriptor is in non blocking mode. So this can lead to some threads never serve a connection.
Also I would advise you to never close same socket in multiple threads. This can lead to very nasty and hard to debug consequences. Either use wrapper and shared_ptr or assign to one of threads a role of 'owner of socket'.
I wonder what happens if two threads call the same function at the same time and the function is a UDP client that sends a text over the socket.
Considering the below code, I have been running it but I have not got any error yet. I wonder if it supposed to be crashed as the threads use the same source (function, variable, IP, port) at the same time, and how do they share the sources? I can imagine that the below code is a wrong usage of multi-threading, could you explain me how the threads should be used so that a thread would use the function only no other threads is using? In other word, how could it be thread-safe?
as an example C code on Linux:
void *thread1_fcn();
void *thread2_fcn();
void msg_send(char *message);
int main(void){
pthread_t thread1, thread2;
pthread_create( &thread1, NULL, thread1_fcn, NULL);
pthread_create( &thread2, NULL, thread2_fcn, NULL);
while(1){}
return 0;
}
void *thread1_fcn(){
while(1){
msg_send("hello");
usleep(500);
}
pthread_exit(NULL);
}
void *thread2_fcn(){
while(1){
msg_send("world");
usleep(500);
}
pthread_exit(NULL);
}
void msg_send(char message[]){
struct sockaddr_in si_other;
int s=0;
char SRV_IP[16] = "192.168.000.002";
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(12346);
si_other.sin_addr.s_addr = htonl(INADDR_ANY);
inet_aton(SRV_IP, &si_other.sin_addr);
sendto(s, message, 1000, 0, &si_other, sizeof(si_other));
close(s);
}
There isn't any problem with your code. Each thread, even if it runs the same code, has a separate stack, so a separate set of variables it works on. No variables are shared.
Since you create and close the socket inside msg_send, nothing special will happen. Everything will work fine.
Your code invokes undefined behavior because the threads pass small string literals as the message argument, but the function tries to send 1000 bytes starting at the message base address.
Since sendto is often a direct call to the operating system, either you will send a lot of garbage over UDP (or worse: security sensitive information!), or the system call will detect an out of bounds memory access and return -1 with errno set to something like EFAULT (likely without having sent any data).
Since message is a string, you should compute its length and then send only that amount (with or without the null terminator; that is up to you. The receiver can reconstruct a null terminated string from the length of the datagram.)
The function raises no concurrency issues, though.
The sendto function is safe even if multiple threads call it on the same socket. If you do that on a stream socket, though, you will likely run into problems with the data being interleaved into the byte stream in unpredictable ways.
I'm trying to create a concurrent TCP server which accepts multiple(N connections) where N is known.(e.g.N=8) So I'm trying to create a prethreaded TCP server.
.....
for(i=0;i<NUMBER_OF_CONNECTIONS;i++)
{
CreateThreads(i);
}
return 0;
}
//Create threads to handle the connection
void CreateThreads( int i )
{
pthread_create(&thread_tid[i], NULL, thread_function, (void *) i);
return;
}
void* thread_function(void *arg)
{
puts("In thread_function");
int client_soc,clilen;
struct sockaddr_in *clientaddr;
if( (clientaddr = malloc(addrlen)) == NULL)
printf("malloc Error\n");
printf("thread %d starting\n", (int) arg);
while(1)
{
clilen = sizeof(struct sockaddr_in);
pthread_mutex_lock(&mlock);
puts("Calling accept \n");
if ( (client_soc = accept(socket_desc, (struct sockaddr *)&clientaddr,(socklen_t*)&clilen)) < 0)
{
printf("accept error\n");
}
pthread_mutex_unlock(&mlock);
printf("Process Request...calling connection handler \n");
connection_handler(client_soc); /* process request */
close(client_soc);
}
}
//This will handle connection for each client
void *connection_handler(void *socket_desc)
{
//Receive and process.....
return 0;
}
In the above code threads are created and the thread_function() gets called but it doesn't work as expected. The program comes to an end after calling the thread_function() till then a few threads get created.
I actually want the "N" number of threads to get created and wait for clients to connect(using accept()). Once connected i want to receive/collect data (or) sending commands etc. That's the reason i have connection_handler() but i'm stuck before that.
Can any one pls try to correct the thread_function() function ? I'm kind of getting stuck here.Thanks.
UPDATE
The program is based on the
http://www.cse.fau.edu/~jie/research/publications/Publication_files/roussevwu.pdf
Look at section 3.2 for using lock and accept.
The program comes to an end after calling the thread_function()
The problem is that after you create the threads the main thread falls through and ends the program. You should call pthread_join.
There's a problem with your approach. In your code you lock mlock and then you accept(2). You are calling a blocking function in a critical section. This severely limits parallelism, thus defeating much of the purpose of the threads.
You could try an approach where the main thread accepts and dispatches the new sockets to threads.
I'm trying to grasp the concepts of multithreading programming, and I think I'm doing well, but then I've found the following code for a simple echo server:
http://www.cs.utah.edu/~swalton/listings/sockets/programs/part2/chap7/echo-thread.c
And I'm thinking that the code is wrong, because it uses the same main local variable to store the data socket for each incoming connection. In particular, Im concerned about this part of main():
while (1)
{ int client, addr_size = sizeof(addr);
pthread_t child;
client = accept(sd, (struct sockaddr*)&addr, &addr_size);
printf("Connected: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
if ( pthread_create(&child, NULL, Child, &client) != 0 )
perror("Thread creation");
else
pthread_detach(child); /* disassociate from parent */
}
As far as I understand, the variable client, local to the while loop, is allocated at exactly the same address in each iteration of the loop. So, when the first client is accepted, the thread receives &client, and when the second client is accepted, the value of client is overwritten with the new data socket, and this can have side-effects in the thread which is already running on the first client.
Observing the code of the function Child, which is the service thread, I can see that the argument is copied into a local variable:
void* Child(void* arg)
{ char line[100];
int bytes_read;
int client = *(int *)arg;
...etc...
and probably the author thought that this copy allows him to later tamper with the main client variable, but IMHO this can cause a race condition. If a second client arrives while the first thread is copying this variable, the value copied can be corrupt.
Am I right?
Yes, you are correct. There are two obvious ways to fix this:
Pass client to the thread instead of &client.
Allocate a new integer on the heap and pass its address to the thread and let the thread free it when it's done with it.
Yes, you are right.
You can demonstrate that you're right by adding a long sleep before int client = *(int*)arg; and connecting to the server two times while the first client thread.