除了上文将的通过fork多进程socket server模型外, 另一种方法是使用select系统调用。当然,也可以对上文的fork进行修改,例如使用pthread创建线程来完成具体工作。
两种方法各有优缺点,都不是最优解决方案。但没种解决方案都不是绝对的,我们可以混合使用各种解决方案来完成,关键是能够理解socket,select,多线程,多进程的本质。相对于多进程fork的方式,我更喜欢使用pthread多线程,原因之一是pthread的代价更低,更重要的原因是多线程可以共享数据,省去了多进程之间通信的代价。
多进程socket server例程:http://www.9say.com/2009/01/multi-process-socket-server-demo-example/
以下是使用select多路复用的socket server模型的一个例子:
/**
* @brief: server.c
*
* A simplest tcp connection example of server side.
* use select to accept multi-client connections.
*
* guotie.9(at)gmail.com
*
*/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#define TRANSFER_PORT 6688
#define MAX_LISTEN 12
int init_transfer();
void fini_transfer();
int recv_data(int sock, char *buf, int len);
int sig_handler(void);
void sig_handler_func(int sig);
int select_conns();
int transfer_sock;
int init_transfer()
{
int sock = -1;
struct sockaddr_in addr;
printf(”init transfer ……/n”);
sock = socket(PF_INET, SOCK_STREAM, 0);
if(-1 == sock)
{
perror(”Failed to create socket./n”);
return -1;
}
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(”0.0.0.0″);
addr.sin_port = htons(TRANSFER_PORT);
if(-1 == bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)))
{
perror(”Failed to bind socket./n”);
return -1;
}
if(-1 == listen(sock, MAX_LISTEN))
{
printf(”Failed to bind socket. errno: %d/n”, errno);
return -1;
}
transfer_sock = sock;
printf(” %s: init transfer socket %d …… success/n”, __FUNCTION__, sock);
return 0;
}
void fini_transfer()
{
int ret;
ret = shutdown(transfer_sock, SHUT_RDWR);
ret = close(transfer_sock);
if(ret < 0)
perror(”/nfini_transfer: “);
else
printf(”/n/n %s: success shutdown transfer socket!/n/n”, __FUNCTION__);
}
int recv_data(int sock, char *buf, int len)
{
int l = 0;
memset(buf, 0, len);
l = recv(sock, buf, len, 0);
if(0 > l)
{