A simple server, using poll() for study:
Code:
// server.c
// Compile with:
// $ cc -O2 -pthread -o server server.c
//
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <poll.h>
#include <string.h>
#include <arpa/inet.h>
// Defines max connections backlog.
// Don't use more then SOMAXCONN (128 on linux), unless you did some tweaking on procfs.
#define MAXCONN 16
// the argument void* won't be a pointer, but the value of the socket's file descriptor.
// Thread function will deal with the socket and close it, when finished...
//
// OBS: To get the peer address/port use getpeername().
static void *thread_func ( void * );
int main ( void )
{
int listen_fd, conn_fd, n;
// Used to bind listening socket to 0.0.0.0:8080.
struct sockaddr_in sin = { .sin_family = AF_INET, .sin_port = htons ( 8080 ) };
pthread_t tid;
pthread_attr_t attr;
/* This is necessary only for non-ephemeral ports (1~1023)... */
//if ( getuid() != 0 )
//{
// fputs ( "ERROR: Must be root!\n", stderr );
// return EXIT_FAILURE;
//}
// Create listening socket...
if ( ( listen_fd = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == -1 )
{
perror ( "socket()" );
return EXIT_FAILURE;
}
puts ( "TCP socket created" );
// Allow reusage of address.
n = 1;
setsockopt ( listen_fd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n );
// Binds this socket to 'local' interface.
if ( bind ( listen_fd, ( struct sockaddr * ) &sin, sizeof sin ) == -1 )
{
perror ( "bind()" );
close ( listen_fd );
return EXIT_FAILURE;
}
puts ( "Socket bounded to 0.0.0.0:8080" );
// Start listening socket... (this is not a blocking call).
if ( listen ( listen_fd, MAXCONN ) == -1 )
{
perror ( "listen()" );
close ( listen_fd );
return EXIT_FAILURE;
}
else
{
puts ( "Listening..." );
while ( 1 )
{
struct pollfd pfd = { .fd = listen_fd, .events = POLLIN };
// This is a blocking call if listen_fd isn't ready to be read.
// I'm ignoring errors here...
if ( poll ( &pfd, 1, 0 ) == 1 )
{
// Finally accepts the connection and create the thread...
if ( ( conn_fd = accept ( listen_fd, NULL, NULL ) ) != -1 )
{
printf ( "Socked [%d] connected.\n", conn_fd );
pthread_attr_init ( &attr );
pthread_attr_setdetachstate ( &attr, PTHREAD_CREATE_DETACHED );
// Note: Passing the socket to the thread in a non portable way!
// This is safe if sizeof(int) <= sizeof(void *)...
pthread_create ( &tid, &attr, thread_func, ( void * ) conn_fd );
}
}
}
}
// will never get here!
close ( listen_fd );
return EXIT_SUCCESS;
}
// Simple thread.
// I'm not checking for errors here for simplicity...
void *thread_func ( void *argp )
{
int sock_fd;
struct sockaddr_in sin;
socklen_t len;
char str[INET_ADDRSTRLEN];
static const char * const msg = "Test...\n";
sock_fd = ( int ) argp;
send ( sock_fd, msg, strlen ( msg ), 0 );
len = sizeof sin;
getpeername ( sock_fd, ( struct sockaddr * ) &sin, &len );
inet_ntop ( AF_INET, &sin.sin_addr, str, sizeof str );
printf ( "Message sent to %s:%u\n", str, ntohs ( sin.sin_port ) );
close ( sock_fd );
printf ( "Socket [%d] closed.\n", sock_fd );
return NULL;
}
Test using telnet:
Code:
$ telnet <addr> 8080
[]s
Fred