您的位置:首页 > 运维架构 > Linux

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 <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 ;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: