下面的程序是创建n个打印进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <wait.h>
int main(void){
int t=0;
while(1){ //循环一次,父进程创建一新进程
pid_t pid=fork(); //从这句后就是主程序创建一新进程,每个线程pid值选择自己执行的代码
if(pid==0){ //子进程
while(1){
printf("%d:%d\n",getpid(),t);
t++;
sleep(1);
}
}else{ //父进程
sleep(5);
}
}
}
在这个程序的基础上就会理解服务器的并行接收客户端的原理了,这种属于批量创建新进程,每个新进程执行相同的代码。
采用多进程的并发服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int main(void){
struct sockaddr_in serv,*p;
memset(&serv,0,sizeof(serv));
p=&serv;
p->sin_family=AF_INET;
p->sin_addr.s_addr=htonl(INADDR_ANY);
p->sin_port=htons(3000);
int sk=socket(PF_INET,SOCK_STREAM,0);
if(sk==-1){
puts("socket error\n");
exit(1);
}
int opt=1;
setsockopt(sk,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,sizeof(opt)); //服务器地址复用
if(bind(sk,(struct sockaddr*)&serv,sizeof(serv))==-1){
puts("bind error\n");
exit(1);
}
if(listen(sk,10)==-1){
puts("listen error\n");
exit(1);
}
puts("listening port\n");
int n=0;
while(n<50){
pid_t pid=fork(); //父进程创建子进程,新进程数控制50个
if(pid==0){
while(1){
int ck=accept(sk,NULL,NULL);
if(ck==-1){
puts("accept error\n");
exit(1);
}
//-----------------------------------------------------------------
int t=0; //发送一个自增数到客户端
while(1){
write(ck,&t,sizeof(t));
sleep(1); //暂停1秒
t++;
}
}
}else{ //父进程不执行代码,直接跳到accept状态
n++;
}
}
while(1){ //父进程产生50个新进程后循环等待,防止主程序退出,中止产生的新进程中止运行
;
}
return 0;
}
此程序一次产生50个accept新进程,所以可以同时接收50个客户端的接入。此程序未加入新进程的退出机制。
加入子进程退出机制的多进程并发服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <wait.h>
int main(void){
struct sockaddr_in serv,*p;
memset(&serv,0,sizeof(serv));
p=&serv;
p->sin_family=AF_INET;
p->sin_addr.s_addr=htonl(INADDR_ANY);
p->sin_port=htons(3000);
int sk=socket(PF_INET,SOCK_STREAM,0);
if(sk==-1){
puts("socket error\n");
exit(1);
}
int opt=1;
setsockopt(sk,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,sizeof(opt)); //服务器地址复用
if(bind(sk,(struct sockaddr*)&serv,sizeof(serv))==-1){
puts("bind error\n");
exit(1);
}
if(listen(sk,10)==-1){
puts("listen error\n");
exit(1);
}
puts("listening port\n");
int stat;
while(1){
int ck=accept(sk,NULL,NULL); //父进程停留在这里,如连接到客户端,则产生一新子进程
if(ck==-1){
puts("accept error\n");
continue;
}else{
puts("one client linking...");
}
pid_t pid=fork();
if(pid==0){ //子进程开始
int t=0;
while(t<10){
write(ck,&t,sizeof(t));
sleep(1);
t++;
}
close(sk);
close(ck);
exit(0); //非常重要,子进程发出停止信号
}
close(ck); //非常重要,如没有这句,客户端不退出
waitpid(-1,&stat,WNOHANG); //父进程关闭停止的子进程
}
return 0;
}
1此程序accept在fork语句前,所以不会一次生成多个子进程,而是连接一个客户端后才生成一个新进程。