TCP/IP网络编程学习(10):利用信号处理技术消灭僵尸进程和基于多任务的并发处理器

本文主要是介绍TCP/IP网络编程学习(10):利用信号处理技术消灭僵尸进程和基于多任务的并发处理器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

利用信号处理技术消灭僵尸进程

子进程终止时产生SIGCHLD信号。就可以捕捉信号终止子进程。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>void read_childproc(int sig){//子进程终止调用该函数int status;pid_t id=waitpid(-1, &status, WNOHANG);//将子进程正常终止if(WIFEXITED(status)){printf("Removed proc id: %d \n", id);printf("Child send: %d \n", WEXITSTATUS(status));}
}int main(int argc, char *argv[])
{pid_t pid;struct sigaction act;act.sa_handler=read_childproc;sigemptyset(&act.sa_mask);act.sa_flags=0;sigaction(SIGCHLD, &act, 0);pid=fork();if(pid==0){puts("Hi! I'm child process");sleep(10);//等待10s终止return 12;}else{   printf("Child proc id: %d \n", pid);pid=fork();if(pid==0){puts("Hi! I'm child process");sleep(10);exit(24);}else{int i;printf("Child proc id: %d \n", pid);for(i=0; i<5; i++){puts("wait...");sleep(5);}}}return 0;
}

基于多任务的并发服务器

在这里插入图片描述
每当有客户端请求服务时,服务器都创建子进程以提供服务。

  1. 服务器端(父进程)通过调用 accept画数受理连接请求 。
  2. 此时获取的套接字文件描述符创建并传递给子进程 。(因为子进程会复制父进程拥有的所有资源 。实际上根本不用另外经过传递文件描述符的过程 。)
  3. 子进程利用传递来 的文件描述符提供服务 。
while(1){adr_sz=sizeof(clnt_adr);clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);if(clnt_sock==-1)continue;elseputs("new client connected...");pid=fork();if(pid==-1){close(clnt_sock);continue;}if(pid==0){close(serv_sock);while((str_len=read(clnt_sock, buf, BUF_SIZE))!=0)write(clnt_sock, buf, str_len);close(clnt_sock);puts("client disconnected...");return 0;}elseclose(clnt_sock);}

通过fork函数复制文件描述符

套接字属于操作系统,fork子进程只是将父进程的文件描述符拿了过去。进程拥有代表相应套接字的文件描述符。父进程将2个套接字(一个是服务器端套接字,另一个是与客户端连接的套接字)文件描述符复制给子进程 。
在这里插入图片描述

1个套接字中存在2个文件描述符时,只有2个文件描述符都终止 (销毁)后,才能销毁套接字 。如果维持阁中的连接状态,即使子进程销毁了与客户端连接的套接字文件描述符,也无法完全销毁套接字(服务器端套接字同样如此)。 因此,调用fork函数后,要将无关的套接字文件描述符关掉,

在这里插入图片描述

一次accept就会创建一个套接字。

分割TCP的I/O程序

传输数据后需要等待服务器端返回的数据,因为程序代码中重复调用了 read和write函数 。 只能能这么写的原因之一是,程序在 1 个进程中运行 。 但现在可以创建多个进程,因此可以分割数据收发过程 。 客户端的父进程负责接收数据,额外创建的子进程负责发送数据 。 分割后,不同进程分别负责输入和输出,这样无论客户端是否从服务器端接收完数据都可以进行传输 。
在这里插入图片描述
之前的回声客户端要接收到服务器的数据才发数据,现在可以连发数据。
在这里插入图片描述
分割I/O后的客户端发送数据时不必考虑接收数据的情况,因此可以连续发送数据,由此提高同一时间内传输的数据量 。 这种差异在网速较慢时尤为明显 。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 30
void error_handling(char *message);
void read_routine(int sock, char *buf);
void write_routine(int sock, char *buf);int main(int argc, char *argv[])
{int sock;pid_t pid;char buf[BUF_SIZE];struct sockaddr_in serv_adr;if(argc!=3) {printf("Usage : %s <IP> <port>\n", argv[0]);exit(1);}sock=socket(PF_INET, SOCK_STREAM, 0);  memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=inet_addr(argv[1]);serv_adr.sin_port=htons(atoi(argv[2]));if(connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)error_handling("connect() error!");pid=fork();if(pid==0)write_routine(sock, buf);//子进程程用来写else read_routine(sock, buf);//父进程用来读close(sock);return 0;
}void read_routine(int sock, char *buf)
{while(1){int str_len=read(sock, buf, BUF_SIZE);if(str_len==0)return;buf[str_len]=0;printf("Message from server: %s", buf);}
}
void write_routine(int sock, char *buf)
{while(1){fgets(buf, BUF_SIZE, stdin);if(!strcmp(buf,"q\n") || !strcmp(buf,"Q\n")){	shutdown(sock, SHUT_WR);return;}write(sock, buf, strlen(buf));}
}
void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}

这篇关于TCP/IP网络编程学习(10):利用信号处理技术消灭僵尸进程和基于多任务的并发处理器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/318773

相关文章

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

Ubuntu固定虚拟机ip地址的方法教程

《Ubuntu固定虚拟机ip地址的方法教程》本文详细介绍了如何在Ubuntu虚拟机中固定IP地址,包括检查和编辑`/etc/apt/sources.list`文件、更新网络配置文件以及使用Networ... 1、由于虚拟机网络是桥接,所以ip地址会不停地变化,接下来我们就讲述ip如何固定 2、如果apt安

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

查询SQL Server数据库服务器IP地址的多种有效方法

《查询SQLServer数据库服务器IP地址的多种有效方法》作为数据库管理员或开发人员,了解如何查询SQLServer数据库服务器的IP地址是一项重要技能,本文将介绍几种简单而有效的方法,帮助你轻松... 目录使用T-SQL查询方法1:使用系统函数方法2:使用系统视图使用SQL Server Configu

使用Java实现获取客户端IP地址

《使用Java实现获取客户端IP地址》这篇文章主要为大家详细介绍了如何使用Java实现获取客户端IP地址,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 首先是获取 IP,直接上代码import org.springframework.web.context.request.Requ

Linux环境变量&&进程地址空间详解

《Linux环境变量&&进程地址空间详解》本文介绍了Linux环境变量、命令行参数、进程地址空间以及Linux内核进程调度队列的相关知识,环境变量是系统运行环境的参数,命令行参数用于传递给程序的参数,... 目录一、初步认识环境变量1.1常见的环境变量1.2环境变量的基本概念二、命令行参数2.1通过命令编程

Linux之进程状态&&进程优先级详解

《Linux之进程状态&&进程优先级详解》文章介绍了操作系统中进程的状态,包括运行状态、阻塞状态和挂起状态,并详细解释了Linux下进程的具体状态及其管理,此外,文章还讨论了进程的优先级、查看和修改进... 目录一、操作系统的进程状态1.1运行状态1.2阻塞状态1.3挂起二、linux下具体的状态三、进程的

C#多线程编程中导致死锁的常见陷阱和避免方法

《C#多线程编程中导致死锁的常见陷阱和避免方法》在C#多线程编程中,死锁(Deadlock)是一种常见的、令人头疼的错误,死锁通常发生在多个线程试图获取多个资源的锁时,导致相互等待对方释放资源,最终形... 目录引言1. 什么是死锁?死锁的典型条件:2. 导致死锁的常见原因2.1 锁的顺序问题错误示例:不同

C++实现获取本机MAC地址与IP地址

《C++实现获取本机MAC地址与IP地址》这篇文章主要为大家详细介绍了C++实现获取本机MAC地址与IP地址的两种方式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 实际工作中,项目上常常需要获取本机的IP地址和MAC地址,在此使用两种方案获取1.MFC中获取IP和MAC地址获取