Find the answer to your Linux question:
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, ...
  1. #1
    Just 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
    Code:
    /*
     * 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
    server.cpp
    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);
    														}

  2. #2
    Linux Guru Rubberman's Avatar
    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!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
...