注意:
accept()本身就可以实现单一的连接,也就是说他本身就可以实现互斥。当有N个进程阻塞在accept()位置的时候,只有一个进程能正常连接,其他进程依然阻塞。
此处静态进程池的缺点:
此处进程池中有4个进程在同时准备接收C端数据请求,也就是说该S端程序,最多也只能够同时对接4个C端,而如果一下来了一万个C端请求,那么此时也只能一次性处理四个C端,下一次再处理四个,也就是四个 四个的处理,显然是不够的。所以如果需要 继续优化,可以使用动态内存池,即 保证线程池中至少有n1个进程在空闲等待接收请求,最大有n2个进程同时工作,这样就比较有弹性。
server.c
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include "proto.h"
#define IPSTRSIZE 40
#define BUFSIZE 1024
#define PROCNUM 4
static void server_loop(int sd);
static void server_job(int sd)
{
char buf[BUFSIZE];
int len;
len = sprintf(buf,FMT_STAMP,(long long)time(NULL));
if(send(sd,buf,len,0) < 0)
{
perror("send()");
exit(1);
}
}
int main()
{
int sd;
pid_t pid;
struct sockaddr_in laddr;
sd = socket(AF_INET,SOCK_STREAM,0/*IPPROTO_TCP*/);
if(sd < 0)
{
perror("soccket()");
exit(1);
}
laddr.sin_family = AF_INET;
laddr.sin_port = htons(atoi(SERVERPORT));
inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr);//0.0.0.0:any address
if(bind(sd,(void *)&laddr,sizeof(laddr)) < 0)
{
perror("bind");
exit(1);
}
if(listen(sd,200) < 0)
{
perror("listen");
exit(1);
}
for(int i=0; i<PROCNUM; i++)
{
pid = fork();
if(pid < 0)
{
perror("fork()");
exit(1);
}
if(pid == 0)
{
server_loop(sd);
exit(0);
}
for(i = 0; i<PROCNUM; i++)
wait();
close(sd);
exit(0);
}
}
static void server_loop(int sd)
{
struct sockaddr_in raddr;
socklen_t raddr_len;
int newsd;
char ipstr[IPSTRSIZE];
/* !!!! */
raddr_len = sizeof(raddr);
while(1)
{
newsd = accept(sd,(void *)&raddr,&raddr_len);
if(newsd < 0)
{
perror("accept");
exit(1);
}
inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE);
printf("[%d]Client %s:%d\n",getpid(),ipstr,ntohs(raddr.sin_port));
server_job(newsd);
close(newsd);
}
close(sd);
}