C 多进程

参考:https://blog.csdn.net/wucz122140729/article/details/105113379编程

在liunx中一些与进程相关的命令:服务器

ps 查看当前终端的进程数据结构

ps -ef 查看系统的所有进程多线程

ps -ef |grep test查看系统的所有进程而且包含test字符的记录socket

在上面的查询结果中各个字段的意义:UID :启动进程的操做系统用户。PID :进程编号。PPID :进程的父进程的编号。C :CPU使用的资源百分比。STIME :进程启动时间。CMD :执行的是什么指令。函数

 

 

在C语言中用getpid()库函数来获取当前程序运行时的进程编号。操作系统

如:.net

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>线程

int main()
{
printf("本程序的进程编号是:%d\n",getpid());
}blog

 

在C的代码中开启新的进程,进行多进程编程,主要是使用fork()函数,这个函数执行后会开启一个新的子进程,该子进程会复制本进程在执行fork()函数前的全部数据。调用fork()函数后,后面的代码就会有两个进程分别来执行,就是说后面的代码会被执行两次,彼此之间互不干扰。

fork()函数的返回值,是一个整数。在父进程中返回值是子进程的编号,在子进程中返回值是0。因此在后面运行的代码中就能够经过判断fork()函数的返回值来判断这次运行是父进程仍是子进程。

如:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
printf("本程序的进程编号是:%d\n",getpid());

int ipid=fork();

printf("pid=%d\n",ipid);

if (ipid!=0) printf("父进程编号是:%d\n",getpid());
else printf("子进程编号是:%d\n",getpid());

}

 

多进程的应用。咱们能够利用多线程将以前的那个socket简单的聊天通信作成多线程的,便可以容许多个客户端来链接个人服务器端。客户端的代码不用修改,主要是修改服务器端的代码。

基本思想是,咱们利用主线程来专门监听来链接的客户端,当监听到有一个客户端链接上来后就开启一个子线程来与该链接上来的客户端进行通信。主线程则继续监听客户端的链接。这样就为每个链接上来的客户端开辟了一个子线程来进行通讯,就不会出现线程的堵塞。

服务器端加上多线程后的代码:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>



int main()
{

  // signal(SIGCHLD,SIG_IGN);  // 忽略子进程退出的信号,避免产生僵尸进程

  // 第1步:建立服务端的socket。
  int listenfd = socket(AF_INET,SOCK_STREAM,0);  

  // 第2步:把服务端用于通讯的地址和端口绑定到socket上。
  struct sockaddr_in servaddr;    // 服务端地址信息的数据结构。
  memset(&servaddr,0,sizeof(servaddr));
  servaddr.sin_family = AF_INET;  // 协议族,在socket编程中只能是AF_INET。
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);          // 任意ip地址。
  //servaddr.sin_addr.s_addr = inet_addr("118.89.50.198"); // 指定ip地址。
  servaddr.sin_port = htons(5051);  // 指定通讯端口。
  if (bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) != 0 )
  { perror("bind"); close(listenfd); return -1; }

  // 第3步:把socket设置为监听模式。
  if (listen(listenfd,5) != 0 ) { perror("listen"); close(listenfd); return -1; }
  // 第4步:接受客户端的链接。

  while(1){
     int  clientfd;                  // 客户端的socket。
     int  socklen=sizeof(struct sockaddr_in); // struct sockaddr_in的大小
     struct sockaddr_in clientaddr;  // 客户端的地址信息。
     clientfd=accept(listenfd,(struct sockaddr *)&clientaddr,(socklen_t*)&socklen);
     printf("客户端(%s)已链接。\n",inet_ntoa(clientaddr.sin_addr));

     if(fork()>0) {continue;close(clientfd); }  // 父进程回到while,继续Accept。由于父进程不须要用clientfd与客户端进行通讯
     
     close(listenfd);//这里关闭掉监听的socket,由于子进程会复制父进程中全部的数据,而监听的socket再子进程中是没有用的,因此这里关闭掉释放资源
      // 第5步:与客户端通讯,接收客户端发过来的报文后,回复ok。
     char buffer[1024];
     while (1)
     {
       memset(buffer,0,sizeof(buffer));
       if (recv(clientfd,buffer,sizeof(buffer),0)<=0) break;   // 接收客户端的请求报文。
       printf("接收:%s\n",buffer);
       memset(buffer,0,sizeof(buffer));

       printf("发送:");
       scanf("%s",buffer);
       if (send(clientfd,buffer,strlen(buffer),0)<=0) break;   // 向客户端发送响应结果。
     }
      printf("客户端已断开链接。\n");

      return 0;  // 或者exit(0),子进程退出。
     }
}
加上signal(SIGCHLD,SIG_IGN);  这一句的做用是为了清理掉僵尸进程,僵尸进程就是子进程再return或者exit以后,若是父进程还在执行。其实是没有彻底将子进程所占用的资源清理掉的。加上这句代码后能够清除掉这些僵尸进程。
相关文章
相关标签/搜索