为每个客户端创建一个线程
此方式首先服务器端建立一个监听,并阻塞至accetp处,当一个客户端进行连接时,accept函数并激活并返回,此时用fork函数创建一个子进程,由子进程执行客户请求处理程序,而父进程继续监听,等待其他的客户端。此方式会创建很多的进程,进程个数受具体的操作系统的限制。这种并发服务器的缺点在于创建一个子进程花费的CPU时间较多,如现在的WEB服务一天需要处理百万计的连接,为每个连接创建一个子进程就会浪费很多的CPU时间,此可以通过预先创建进程的方法来解决,此将作为单独的一个模块说明。
例子:回射服务器,接受客户端的请求,并读取客户的数据并原样返回,此程序在CentOS 5.0中测试通过。
服务器程序:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/select.h>
#include <strings.h>
#include <errno.h>
#include <stdlib.h>
#define SERV_PORT 2003
#define MAXLINE 1024
#define LISTENQ 4
/* 根据端口号建立连接 */
int makeListenByPort(short port)
{
int listenfd;
struct sockaddr_in servaddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
listen(listenfd, LISTENQ);
return listenfd;
}
/* 客户请求处理函数 */
void requestProductFunc(int connfd)
{
char buf[MAXLINE];
int n;
for(;;) {
if((n = read(connfd, buf, MAXLINE)) == 0) {
close(connfd);
printf("client is quit\n");
}else{
write(connfd, buf, n);
}
}
}
int main(int argc, char **argv)
{
int listenfd, connfd, maxfd, sockfd;
char buf[MAXLINE];
struct sockaddr_in cliaddr;
int i;
int clilen, adrlen;
pid_t child;
listenfd = makeListenByPort(SERV_PORT);
adrlen = sizeof(struct sockaddr);
for(;;) {
clilen = adrlen;
if((connfd = accept(listenfd, (struct sockaddr *)&cliaddr,&clilen)) < 0){
/* 如果是被中信号中断则继续*/
if(errno == EINTR)
continue;
else{
printf("accepterror!");
exit(0);
}
}
/* 创建一个线程并调用客户请求处理函数 */
if((child = fork()) == 0) {
close(listenfd);
requestProductFunc(connfd);
exit(0);
}
/* 父进程关闭连接,并继续监听 */
close(connfd);
}
}
客户端程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <strings.h>
#include <string.h>
#define MAXLINE 1024
#define SERV_PORT 2003
void cli_str(FILE *fp, int sockfd)
{
char sendline[MAXLINE];
char recvline[MAXLINE];
memset(recvline, 0x00, sizeof(recvline));
memset(sendline, 0x00, sizeof(sendline));
printf("cli#");
while((fgets(sendline, MAXLINE, fp)) != NULL) {
write(sockfd, sendline, strlen(sendline));
if(read(sockfd, recvline, MAXLINE) == 0) {
printf("str_cli:server terminated prematurely\n");
exit(0);
}
fputs(recvline, stdout);
fflush(stdout);
memset(recvline, 0x00, sizeof(recvline));
printf("cli#");
}
}
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
printf("socket error\n");
exit(0);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
if((connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))== -1) {
printf("connect error\n");
exit(0);
}
cli_str(stdin, sockfd);
exit(0);
}