Linux之并发进程服务器

来源:互联网 发布:云计算的特征是什么 编辑:程序博客网 时间:2024/06/08 23:44

服务器按处理方式可以分为迭代服务器和并发服务器两类。迭代服务器每次只能处理一个客户的请求,他实现简单但效率很低,通常这种服务器被称为迭代服务器

然而在实际应用中,不可能让一个服务器长时间地为一个客户服务,而需要器具有同时处理多个客户请求的能力,这种同时可以处理多个客户请求的服务器称为并发服务器,其效率很高却实现复杂

Linux系统主要提供3种方式支持并发: 进程,线程 以及 I/O多路复用。

1: 进程创建

#include <unistd.h>

pid_t  fork(void);

函数调用失败返回 -1 ,fork函数调用失败主要有两原因 :系统中已经有太多的进程和改实际用户的ID进程超过系统的限制

函数会返回两次 , 子进程ID和父进程ID。

fork调用后,父进程和子进程继续执行fork函数后的指令,是父进程还是子进程先执行是不确定的,这取决于系统内核所使用的调度算法。

fork有两个典型的应用:1 夫,子进程各自执行不同的程序段,这是非常典型的网络服务器。父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork函数产生子进程,又子进程对该请求进行处理,父进程则继续等待下一个客户的服务请求。在这种情况下,父,子进程需要关闭各自不使用描述符。

2  每个进程要执行不同的程序。在这种情况下,子进程在从fork函数发回后立即调用exec函数执行其他程序。

pid_t vfork(void);

和fork函数一样,不同vfork是完全共享创建,新老进程共享同样的资源,完全没有拷贝。当使用vfork函数创建新进程时,父进程将被暂时阻塞,而子进程则可以借用父进程的地址空间运行。这个奇特的状态持续到子进程推出或调用execve函数,至此父进程菜继续执行

#include <stdio.h>#include <sys/types.h>#include <unistd.h>int main(){pid_t child_pid;int i=1;printf("the main program process ID is %d\n",(int)getpid() );child_pid = fork();if( 0 != child_pid  ){i= 0;printf("this is the parent process , with id %d and i= %d \n",(int)getpid(),i );printf("the child's process ID is %d\n",(int)child_pid );}elseprintf("this is the child process , with ID= %d and i = %d\n",(int)getpid(), i);return 1;}
2: 进程终止

#include<sys/wait.h>

pid_t wait(int *staloc);

wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status 返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则参数status 可以设成NULL。子进程的结束状态值请参考下面的waitpid()。

#include <sys/wait.h>

  #include <sys/type.h>

 pid_t waitpid( pid_t pid, int *statloc,int option )

waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程

  结束。如果在调用 waitpid()时子进程已经结束,则 waitpid()会立即
  返回子进程结束状态值。 子进程的结束状态值会由参数 status 返回,
  而子进程的进程识别码也会一起返回。如果不在意结束状态值,则
  参数 status 可以设成 NULL。参数 pid 为欲等待的子进程识别码,
  其他数值意义如下:
  pid<-1 等待进程组识别码为 pid 绝对值的任何子进程。
  pid=-1 等待任何子进程,相当于 wait()。
  pid=0 等待进程组识别码与目前进程相同的任何子进程。
  pid>0 等待任何子进程识别码为 pid 的子进程。

参数option让用户指定附加选项。最常用的选项是WHO_HANG,他通知内核在没有已终止子进程时不要阻塞。

 #include<stdlib.h>  #include<unistd.h>  #include<sys/types.h>  #include<sys/wait.h>  main()  {  pid_t pid;  int status,i;  if(fork()= =0){  printf(“This is the child process .pid =%d\n”,getpid());  exit(5);  }else{     sleep(1);           printf(“This is the parent process ,wait for child...\n”);  pid=wait(&status);  i=WEXITSTATUS(status);  printf(“child’s pid =%d .exit status=%d\n”,pid,i);  }  }
下面是用多进程实现的服务器端实例:

#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#define PORT 1234#define BACKLOG 5#define MAXDATASIZE 1000void process(int connfd, struct sockaddr_in client);int main(){int listenfd,connfd;pid_t pid;struct sockaddr_in server;struct sockaddr_in client;if( (listenfd = socket(AF_INET, SOCK_STREAM, 0) ) == -1 ){printf("socket fail \n ");_exit(1);}setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,(const void *)SO_REUSEADDR,sizeof(SO_REUSEADDR) );bzero( (void *)&server,sizeof(server) );server.sin_family = AF_INET;server.sin_port = htons(PORT);server.sin_addr.s_addr = htonl(INADDR_ANY);           //服务器可能有许多网卡,但是INADDR_ANY 设置默认网卡IP  也可设为172.16.1.166(本人pc机上的固定IP)if( bind( listenfd,(struct sockaddr *)&server ,sizeof(server) ) == -1 ){printf(" bind fail \n");_exit(1);}if( listen(listenfd, BACKLOG) < 0){printf("listen fail  \n");_exit(1);}//-------------开始监听客户端-----------------------------------------------while(1){//int len = sizeof(client);if( (connfd = accept(listenfd, (struct sockaddr *)&client, &(int){sizeof client}) ) == -1 )   //如果接受成功,那么client结构体将会存储远程主机的各种信息{printf("accept fail \n");_exit(1);}if( (pid = fork() ) < 0 ){printf("fork fail \n");_exit(1);}else if(pid == 0){close(connfd);      //必须关闭connfd,connfd再次用来接受下一个远程主机的信息process(connfd,client);       //子进程对请求进程处理,在process函数中处理,之前必须关闭套接字}else{close(connfd);    //如果是父进程 这关闭套接字。跳出if循环,继续监听下次请求continue;}}}void process(int connfd, struct sockaddr_in client){int num;char cli_name[MAXDATASIZE];char databuf[MAXDATASIZE];printf("get data from : %s", inet_ntoa( client.sin_addr) );if((num = recv(connfd, cli_name, MAXDATASIZE, 0) ) == 0 ){printf("client disconnected \n");return ;}cli_name[num-1] = '\0';printf("client name is %s \n", cli_name);while( num = recv(connfd, databuf, MAXDATASIZE, 0) ){databuf[num-1] = '\0';printf("get message from client : %s \n",databuf);send(connfd, databuf, strlen(databuf), 0);}return ;}



原创粉丝点击