您的位置:首页 > Web前端

create socket by pthread

2012-05-30 15:42 225 查看
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <errno.h>

//--------------------------------------------------------------------
// Function prototype
//--------------------------------------------------------------------
void signal_handler(int signum);
void *thread_main(void *arg);

//--------------------------------------------------------------------
// Main function
//--------------------------------------------------------------------
int main(int argc, char **argv)
{
int listening_socket;
unsigned short port;
int backlog;

//------------------------------------------------------------------
// Parse command line arguments
//------------------------------------------------------------------
port = (unsigned short) strtol(argv[2], NULL, 10);
backlog = (int) strtol(argv[3], NULL, 10);

//------------------------------------------------------------------
// step 1, create socket
//------------------------------------------------------------------
//int socket(int domain, int type, int protocol);
if ((listening_socket = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
// failed
fprintf(stderr, "[%d]Create new TCP socket failed: %s\n", getpid(), strerror(errno));
exit(1);
}

fprintf(stderr, "[%d]New TCP socket created, listening_socket = %d\n", getpid(), listening_socket);

//------------------------------------------------------------------
// Set SO_REUSEADDR & SO_REUSEPORT options
//------------------------------------------------------------------
int optval;

optval = 1;

//int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
if (setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
{
fprintf(stderr, "[%d]Set socket option SO_REUSEADDR failed: %s\n", getpid(), strerror(errno));
}
else
{
fprintf(stderr, "[%d]Set socket option SO_REUSEADDR successfully.\n", getpid());
}

#ifdef SO_REUSEPORT
optval = 1;

//int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
if (setsockopt(listening_socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)) < 0)
{
fprintf(stderr, "[%d]Set socket option SO_REUSEPORT failed: %s\n", getpid(), strerror(errno));
}
else
{
fprintf(stderr, "[%d]Set socket option SO_REUSEPORT successfully.\n", getpid());
}
#endif

//------------------------------------------------------------------
// step 2, bind
//------------------------------------------------------------------
struct sockaddr_in local_ipv4_address;	// IPv4

memset(&local_ipv4_address, 0, sizeof(local_ipv4_address));

local_ipv4_address.sin_family = AF_INET;	// IPv4
local_ipv4_address.sin_port = htons(port);	// Network byte order

// int inet_pton(int af, const char *src, void *dst);
inet_pton(AF_INET, argv[1], &local_ipv4_address.sin_addr);

// Bind all interfaces
//local_ipv4_address.sin_addr.s_addr = INADDR_ANY;

//int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
if (bind(listening_socket, (struct sockaddr *) &local_ipv4_address, sizeof(local_ipv4_address)) < 0)
{
fprintf(stderr, "[%d]Bind to %s:%d failed: %s\n", getpid(), argv[1], port, strerror(errno));
close(listening_socket);
exit(1);
}

fprintf(stderr, "[%d]Bound to %s:%d successfully.\n", getpid(), argv[1], port);

//------------------------------------------------------------------
// step 3, listen
//------------------------------------------------------------------
//int listen(int sockfd, int backlog);
if (listen(listening_socket, backlog) < 0)
{
fprintf(stderr, "[%d]Listen on %s:%d failed: %s\n", getpid(), argv[1], port, strerror(errno));
close(listening_socket);
exit(1);
}

fprintf(stderr, "[%d]Listen on %s:%d successfully.\n", getpid(), argv[1], port);
fprintf(stderr, "[%d]Waiting for incomming connections ...\n", getpid());

//------------------------------------------------------------------
// Register signal handler
//------------------------------------------------------------------
struct sigaction act, oact;

#if 0
struct sigaction
{
void (*sa_handler) (int);
void (*sa_sigaction) (int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer) (void);
};
#endif

memset(&act, 0, sizeof(act));

act.sa_handler = signal_handler;
//int sigemptyset(sigset_t *set);
sigemptyset(&act.sa_mask);
act.sa_flags = 0;

//int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
sigaction(SIGCHLD, &act, &oact);

//------------------------------------------------------------------
// Main loop
//------------------------------------------------------------------
for (;;)
{
//----------------------------------------------------------------
// accept(), create a new_connected_socket
//----------------------------------------------------------------
/*
* The accept() system call is used  with  connection-based socket types (SOCK_STREAM, SOCK_SEQPACKET).
*
* It extracts the first connection request on the queue of pending connections, creates a new connected
* socket, and returns a new file descriptor referring to that socket.
*
* The newly created socket is not in the listening state(in ESTABLISHED state)
*
* The original socket sockfd is unaffected by this call(still in LISTEN state)
*/

int new_connected_socket;
struct sockaddr_in peer_ipv4_address;
socklen_t peer_ipv4_address_length;

// peer_ipv4_address_length is a value-result parameter
peer_ipv4_address_length = sizeof(peer_ipv4_address);

//int accept(int sockfd, struct sockaddr *addr, socklen_t * addrlen);
if ((new_connected_socket = accept(listening_socket, (struct sockaddr *) &peer_ipv4_address, &peer_ipv4_address_length)) < 0)
{
// failed
if (errno == EINTR)
{
// Interrupted by signal
continue;
}
else
{
// TODO: check other error code
}

fprintf(stderr, "[%d]Accept new connections on socket %d failed: %s\n", getpid(), listening_socket, strerror(errno));
break;
}
else
{
// success
char peer_ipv4_address_string[] = "ddd.ddd.ddd.ddd";

//const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
inet_ntop(AF_INET, &peer_ipv4_address.sin_addr, peer_ipv4_address_string, sizeof(peer_ipv4_address_string));

fprintf(stderr, "[%d]Accepted a new connection %d from %s:%d.\n", getpid(), new_connected_socket, peer_ipv4_address_string, ntohs(peer_ipv4_address.sin_port));

//--------------------------------------------------------------
// create new thread
//--------------------------------------------------------------
pthread_t tid;
pthread_attr_t attr;
int code;

//int pthread_attr_init(pthread_attr_t *attr);
pthread_attr_init(&attr);

//int pthread_attr_setdetachstate(pthread_attr_t * attr, int detach - state);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

//int pthread_create(pthread_t * restrict thread, const pthread_attr_t * restrict attr, void *(*start_routine) (void *), void *restrict arg);
if ((code = pthread_create(&tid, &attr, thread_main, (void *) &new_connected_socket)) != 0)
{
fprintf(stderr, "[%d]Create new thread failed: %s\n", getpid(), strerror(code));
}
else
{
fprintf(stdout, "[%d]New thread created.\n", getpid());
}

//int pthread_attr_destroy(pthread_attr_t *attr);
pthread_attr_destroy(&attr);
}
}

//------------------------------------------------------------------
// final, close listening_socket
//------------------------------------------------------------------
close(listening_socket);

return 0;
}

void signal_handler(int signum)
{
fprintf(stderr, "[%d]Caught signal %d.\n", getpid(), signum);

pid_t pid;
int status;

//pid_t wait(int *status);
if ((pid = wait(&status)) < 0)
{
// failed
fprintf(stderr, "wait() failed: %s\n", strerror(errno));
}
else
{
fprintf(stderr, "[%d]Child process %d terminated, status = 0x%08x\n", getpid(), pid, status);

// check status
}
}

void *thread_main(void *arg)
{
int fd = *(int *) arg;

//--------------------------------------------------------------
// Compose current time information
//--------------------------------------------------------------
// time_t time(time_t *t);
time_t now = time(NULL);

struct tm *tm;

//struct tm *localtime(const time_t *timep);
tm = localtime(&now);

char buffer[128];

#if 0
struct tm
{
int tm_sec;			/* seconds */
int tm_min;			/* minutes */
int tm_hour;		/* hours */
int tm_mday;		/* day of the month */
int tm_mon;			/* month */
int tm_year;		/* year */
int tm_wday;		/* day of the week */
int tm_yday;		/* day in the year */
int tm_isdst;		/* daylight saving time */
};
#endif

memset(buffer, 0, sizeof(buffer));

//int snprintf(char *str, size_t size, const char *format,...);
snprintf(buffer, sizeof(buffer) - 1, "Current time: %04d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);

//--------------------------------------------------------------
// Send current time to client
//--------------------------------------------------------------
ssize_t n;

//ssize_t write(int listening_socket, const void *buf, size_t count);
if ((n = write(fd, buffer, strlen(buffer))) < 0)
{
fprintf(stderr, "[%d]Send data to client fialed: %s\n", getpid(), strerror(errno));
}
else
{
fprintf(stderr, "[%d]Sent %d bytes (\"%s\" to client successfully.\n", getpid(), n, buffer);
}

//--------------------------------------------------------------
// close new_connected_socket
//--------------------------------------------------------------
close(fd);

pthread_exit((void *) 0);
}

// vim:tabstop=8
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息