Linux之并发进程服务器
2012-11-05 16:51
344 查看
服务器按处理方式可以分为迭代服务器和并发服务器两类。迭代服务器每次只能处理一个客户的请求,他实现简单但效率很低,通常这种服务器被称为迭代服务器。
然而在实际应用中,不可能让一个服务器长时间地为一个客户服务,而需要器具有同时处理多个客户请求的能力,这种同时可以处理多个客户请求的服务器称为并发服务器,其效率很高却实现复杂。
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<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,他通知内核在没有已终止子进程时不要阻塞。
下面是用多进程实现的服务器端实例:
然而在实际应用中,不可能让一个服务器长时间地为一个客户服务,而需要器具有同时处理多个客户请求的能力,这种同时可以处理多个客户请求的服务器称为并发服务器,其效率很高却实现复杂。
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 ); } else printf("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 1000 void 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 ; }
相关文章推荐
- linux网络编程多进程并发服务器
- linux下一个单进程并发服务器的实例 使用select
- linux僵死进程与并发服务器编程
- Linux下一个单进程并发服务器的实例 使用select
- 使用socket的Linux上的C语言helloworld多进程并发服务器
- linux网络编程----->高并发--->多进程并发服务器
- Linux并发回射服务器(二):处理僵死进程
- linux(一)------多进程并发服务器实现(fork)
- 聊聊Linux fork多进程并发服务器模型
- 使用socket的Linux上的C语言helloworld多进程并发服务器
- linux socket多进程并发服务器
- linux下高并发服务器实现(修改用户进程可打开文件数限制ulimit -n)
- 分享:Linux C基于进程并发的服务器简单示例
- 第二十篇:不为客户连接创建子进程的并发回射服务器(poll实现)
- Linux c==网络编程的理论知识-并发服务器,分布式服务器(34)
- 优化Linux的内核参数来提高服务器并发处理能力
- 第15章 高并发服务器编程(4)_守护进程(完结)
- 并发服务器---多进程
- linux 并发服务器模式
- Linux TCP协议使用进程实现并发服务器