Results 1 to 2 of 2
Hi all,
I'm building a simple(?) socket server using threads to serve up a few requests. The spec is such that I have to listen to three ports at once, ...
- 04-19-2010 #1Just Joined!
- Join Date
- Apr 2010
- Posts
- 1
Socket server using pthread doesn't wait for accept() properly
Hi all,
I'm building a simple(?) socket server using threads to serve up a few requests. The spec is such that I have to listen to three ports at once, so I decided to use pthread to create three separate threads that would wait for connections, then spawn new threads to handle them.
The problem is that when I do this, for some reason the program never enters the wait loop and instead terminates (All three threads did get created since the messages get printed properly.) It gets to the line which prints "???", but not the line after the accept() call.
I don't see an open port when I check for one either so I'm 99% sure they're terminating.
Basically I have a main() method which has three calls to pthread_create, which should result in three threads being run that all wait for connections (listenOnPort). After each thread creation I print some info to make sure it's actually being created.
By the way, when I just run listenOnPortwithout threading, the server appears to enter the loop correctly and seems to be waiting for requests. It's only when I run the functions as threads that the problem seems to happen.
The source is attached below. Any help will be appreciated. Much of the code is borrowed from a website (I can't post it because I am new here.) You need not worry about the handler_ methods because those are just methods that are run by the threads themselves.
Also--the original source was in C and I changed it to C++. Should I just use C?
server.h
server.cppCode:/* * server.h * * Created on: Mar 22, 2010 * */ #ifndef SERVER_H_ #define SERVER_H_ #ifndef _REENTRANT #define _REENTRANT /* TCP ports */ const int TIME_PORT = 70001; const int WEB_PORT = 70002; const int INFO_PORT = 70003; #include <stdio.h> #include <iostream> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/uio.h> #include <unistd.h> #include <pthread.h> #include <string> #include <string.h> #include <stdlib.h> #endif /* SERVER_H_ */ void *handle_time_request(void *); void *handle_web_request(void *); void *handle_info_request(void*); void* listenTime(void *); void* listenWeb(void *); void* listenInfo(void *); void* listenOnPort(void *); #endif
Code:#include "server.h" using namespace std; int main(int argc, char *argv[]) { cout << "Starting server" << endl; pthread_t threads[3]; int ret; pthread_attr_t tattr; pthread_create(&threads[0], &tattr, listenOnPort, (void*)70001 ); cout << "Thread 1 created" << endl; pthread_create(&threads[1], NULL, listenOnPort, (void*)70002); cout << "Thread 2 created" << endl; pthread_create(&threads[2], NULL, listenOnPort, (void*)70003); cout << "Thread 3 created" << endl; } void* listenOnPort(void* arg) { while(1) { } int portNo=(int)arg; cout << "Listening on port " << portNo << endl; int sockfd, newsockfd; socklen_t clilen; struct sockaddr_in cli_addr, serv_addr; pthread_t chld_t; if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr,"server: can't open stream socket\n"), exit(0); } else { //cout << "Server: Socket opened" << endl; } memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(portNo); if(bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { fprintf(stderr,"server: can't bind local address\n"), exit(0); } else { //cout << "Successfully bound local address" << endl; } /* set the level of thread concurrency we desire */ pthread_setconcurrency(5); listen(sockfd, 5); cout << "Listening for connections on port " << portNo <<endl; while(1){ //cout << "???" << endl; clilen = sizeof(cli_addr); //cout << "Size of client address: " << clilen << endl; newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); cout << "New socket connection: " << newsockfd << endl; cout << "Accepted connection" << endl; if(newsockfd < 0) { fprintf(stderr,"server: accept error\n"), exit(0); } else { cout << "Successfully accepted socket connection" << endl; } switch(portNo)/* create a new thread to process the incomming request */ { case 70001: { cout <<"Starting handler thread" << endl; pthread_create(&chld_t, 0, handle_time_request, (void *)newsockfd); cout << "Created handler thread" << endl; } case 70002: { pthread_create(&chld_t, 0, handle_web_request, (void *)newsockfd); } case 70003: { pthread_create(&chld_t, 0, handle_info_request, (void *)newsockfd); } /* the server is now free to accept another socket request */ } /* the server is now free to accept another socket request */ } } /* This is the routine that is executed from a new thread */ void* handle_time_request(void *arg) { cout << "Starting handler for time requests" << endl; int mysocfd = (int) arg; char data[100]; int i; printf("Child thread [%d]:", (int)pthread_self(), mysocfd); /* read from the given socket */ read(mysocfd, data, 40); printf("Child thread [%d]: My data = %s\n", (int)pthread_self(), data); /* simulate some processing */ for (i=0;i<1000000*(int)pthread_self();i++); printf("Child [%d]: Done Processing...\n", (int)pthread_self()); printf("Child thread [%d]:", (int)pthread_self()); /* close the socket and exit this thread */ close(mysocfd); pthread_exit((void *)0); } void* handle_info_request(void *arg) { cout << "Starting handler for info requests" << endl; int mysocfd = (int) arg; char data[100]; int i; printf("Child thread [%d]: Socket number = %d\n", (int)pthread_self(), mysocfd); /* read from the given socket */ read(mysocfd, data, 40); printf("Child thread [%d]: My data = %s\n", (int)pthread_self(), data); /* simulate some processing */ for (i=0;i<1000000*(int)pthread_self();i++); printf("Child [%d]: Done Processing...\n", (int)pthread_self()); printf("Child thread [%d]:", (int)pthread_self()); /* close the socket and exit this thread */ close(mysocfd); pthread_exit((void *)0); } void* handle_web_request(void *arg) { cout << "Starting handler for web requests" << endl; int mysocfd = (int) arg; char data[100]; int i; printf("Child thread [%d]: Socket number = %d\n", (int)pthread_self(), mysocfd); /* read from the given socket */ read(mysocfd, data, 40); printf("Child thread [%d]: My data = %s\n", (int)pthread_self(), data); /* simulate some processing */ for (i=0;i<1000000*(int)pthread_self();i++); printf("Child [%d]: Done Processing...\n", (int)pthread_self()); printf("Child thread [%d]:", (int)pthread_self()); /* close the socket and exit this thread */ close(mysocfd); pthread_exit((void *)0); }
- 04-27-2010 #2Linux Guru
- Join Date
- Apr 2009
- Location
- I can be found either 40 miles west of Chicago, or in a galaxy far, far away.
- Posts
- 8,974
I really don't have time to get into this in much detail, but you should use one thread to open the sockets, listen() and accept() connections. This is usually the main thread which will dispatch the connections to other threads that can process them and respond/converse with the sender and then close the connection when appropriate. This all assumes that you are using TCP and not UDP messages. UDP will be handled a bit differently since each message is an entity in itself, whereas TCP are connection oriented streams.
As for the C vs C++ argument, you can use C functions and programs with the C++ compiler. You just have to remember that any local function that needs to have C binding (will be called from another C functions, such as some sort of callback from a C function) must be flagged as such with the extern "C" compiler flag. In any case, there are a LOT of C++ programs that use the standard C libraries, and the Berkeley sockets library is a good case in point, commonly used by such programs. I've used them extensively myself in many, many C++ programs.Sometimes, real fast is almost as good as real time.
Just remember, Semper Gumbi - always be flexible!


Reply With Quote