从入门到入土:基于C语言实现并发Web服务器|父进程子进程|代码展示

此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出。欢迎各位前来交流。(部分材料来源网络,若有侵权,立即删除)
本人博客所有文章纯属学习之用,不涉及商业利益。不合适引用,自当删除!
若被用于非法行为,与我本人无关

代码

服务端

#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<string.h>
#include<netdb.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#define PORT 8900
#define BUF_SIZE 2048
#include<stdlib.h>

int execute(char* command,char* buf);

int main()
{
	int sockfd;
	struct sockaddr_in client;
	struct sockaddr_in server;
	char send_buf[BUF_SIZE];
	char recv_buf[BUF_SIZE];
	char cmd[4096];
	int sendnum;
	int recvnum;
	int length;
	int port;
	int connected;

	memset(send_buf,0,2048);
	memset(recv_buf,0,2048);
	memset(cmd,0,4096);
	port = PORT;
	
	if (-1==(sockfd=socket(AF_INET,SOCK_STREAM,0)))  //change
	{
		perror("[error]:socket connect failed\n");
		exit(1);
	}

	memset(&server,0,sizeof(struct sockaddr_in));
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = htonl(INADDR_ANY);
	server.sin_port = htons(port);

	if (-1==bind(sockfd,(struct sockaddr*)&server,sizeof(struct sockaddr)))
	{
		perror("[error]:binding\n");
		close(sockfd);
		exit(1);
	}

	if(-1==listen(sockfd,10))
	{
		perror("[error]:listien\n");
		close(sockfd);
		return -1;
	}
	
	length = sizeof(struct sockaddr_in);

	while(1)
	{
		memset(recv_buf,0,2048);
		memset(send_buf,0,2048);
		if(-1==(connected=accept(sockfd,(struct sockaddr*)&client,&length)))
		{
			perror("[error]:three shakehands\n");
			close(sockfd);
			return -1;
		}
		//change///
		int pid = fork();
		if((pid=fork())<0)
		{
			printf("fork failed\n");
			_exit(1);
		}
		else if(pid == 0)
		{
			process(connected, client);
			
		}
		else
		{
			close(connected);
			continue;
		}
		close(connected);
	}
	close(sockfd);
	exit(1);
}

int process(int connected, struct sockaddr_in client)
{
	char sendbuf[BUF_SIZE];
	char recvbuf[BUF_SIZE];
	int sendnum = 0;
	int recvnum = 0;
	int cnt;
	int n, fd[2];
	int length = sizeof(struct sockaddr_in);
	char cmd[10];
	char path[2048];
	pid_t pid;
	memset(sendbuf, 0, BUF_SIZE);
	memset(recvbuf, 0, BUF_SIZE);
	
	if(pipe(fd)<0)
		printf("[error]:creat pipe  \n");
		
	while(1)
	{
		if(0>=(recvnum=recv(connected, recvbuf, BUF_SIZE, 0)))
		{
			perror("[error]:recv\n");
			close(connected);
			return -1;
		}
		
		recvbuf[recvnum]='\0';
		printf("子进程pid:%d \n父进程pid:%d\n连接描述符:%d\n",getpid(),getppid(),connected);
		fprintf(stderr, "the command is:%s\n", recvbuf);
		
		if(0==strcmp(recvbuf, "quit"))
		{
			perror("quitting remote controling\n");
                        close(connected);
                        return 0;	
		}
		
		strcpy(cmd,"/bin/");
                strcat(cmd,recvbuf);
                execute(cmd,sendbuf);

                if ('\0'==*sendbuf)
                {
                	memset(cmd,0,sizeof(cmd));
                        strcpy(cmd,"/sbin/");
                        strcat(cmd,recvbuf);
                        execute(cmd,sendbuf);
                        
                        if ('\0'==*sendbuf)
                        {       
                                memset(cmd,0,sizeof(cmd));
                                strcpy(cmd,"/usr/bin/");
                                strcat(cmd,recvbuf);
                                execute(cmd,sendbuf);
                        }
                        
                        if ('\0'==*sendbuf)
                        {       
                                memset(cmd,0,sizeof(cmd));
                                strcpy(cmd,"/usr/sbin/");
                                strcat(cmd,recvbuf);
                                execute(cmd,sendbuf);
                        }
                }
                if ('\0'==*sendbuf)
                        sprintf(sendbuf,"command is not vaild,check it please\n");

                printf("%s\n",sendbuf);
			
		sendnum = send(connected,sendbuf,sizeof(sendbuf),0);
                if (0>sendnum)
                {
                        perror("sending data error\n");
                        continue;
                }
        }
}

int execute(char* command,char* buf)
{
	FILE * 	fp;
	int count;

	if (NULL==(fp = popen(command,"r")))
	{
		perror("[error]:creating pipe\n");
		exit(1);
	}
	
	count = 0 ;

	while(((buf[count] = fgetc(fp))!=EOF)&&count<2047)
		count++;
	
	buf[count]='\0';

	pclose(fp);

	if(0==count)   //change
		printf(buf, "%s cannot execute\n",command);

	return count;
}

客户端

#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<string.h>
#include<netdb.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define PORT 8900
#define BUF_SIZE 2048

void print_usage(char* str)
{
	printf("%s usage :\n",str);
	printf("%s Ipaddr \n");
}
int main(int argc, char** argv)
{
	int sockfd;
	struct sockaddr_in client;
	struct sockaddr_in server;
	char send_buf[BUF_SIZE];
	char recv_buf[BUF_SIZE];  
	int sendnum;
	int recvnum;
	int length;
	int port;


	if(2!=argc)
	{
		print_usage(argv[0]);
		exit(1);	
	}
	
	memset(send_buf,0,2048);
	memset(recv_buf,0,2048);
	port = PORT;
	
	if (-1==(sockfd=socket(AF_INET,SOCK_STREAM,0)))  // change
	{
		perror("generating socket error\n");
		exit(1);
	}	

	memset(&server,0,sizeof(struct sockaddr_in));    //change
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = inet_addr(argv[1]);
	server.sin_port = htons(port);

	if(-1==connect(sockfd, (struct sockaddr*)&server, sizeof(server)))  //change
	{
		perror("connect error\n");
		close(sockfd);
		return -1;
	}
 		
	while(1)
		memset(send_buf,0,2048);
       	memset(recv_buf,0,2048);
		printf("tcp>");   //change
		gets(send_buf);  //change   Don't use 'fgets'!!!!!!!!!!!!
		printf("\n");
		if (0>send(sockfd,send_buf,strlen(send_buf),0))  //change
		{
			perror("error occar in sending data\n");
			break;
		}
		if (0==strcmp(send_buf,"quit"))
		{
			printf("quit...\n");     //change
			break;
		}
		length = sizeof(struct sockaddr);
		recvnum = recv(sockfd,recv_buf,2048,0);
		if(0<recvnum)                          //change
		{
			recv_buf[recvnum]='\0';
			printf("%s\n",recv_buf);
		}
		else{
			continue;
		}
		//printf("%s\n",recv_buf);
	}
	close(sockfd);
	exit(1);
}

运行效果

  • 分别执行三个客户端进程:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 查看服务器输出情况:
    在这里插入图片描述
  • 查看进程结束前后变化:
    在这里插入图片描述
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言实现的支持高并发、超高性能Web服务器源码,可以编译运行,使用高性能HTTP解析器fasterhttp作为其解析核心,在开启Keep-Alive和gzip压缩时(现代浏览器默认开启)性能比nginx约快3倍。 hetao功能: * 支持主流操作系统Linux(基于epoll)、WINDOWS(基于IOCP,暂不支持HTTPS) * 支持HTTP/1.0、HTTP/1.1 * 支持通讯超时控制 * 支持多侦听端口 * 支持多虚拟主机(基于域名) * 支持自定义错误页面 * 支持自定义缺省index文件 * 支持自适应Keep-Alive * 支持自适应gzip、deflate压缩 * 支持HTTPS * 支持反向代理负载均衡(目前支持轮询、最少 连接数算法),支持HTTP与HTTPS互转 * 支持rewrite * 支持优雅重启/重载配置,重启期间完全不中断对外服务 * 支持工作进程绑定CPU * 支持进程 崩溃后自动重启安全机制: * HTTP请求报文合法性校验 * 活跃超时控制(防止僵尸连接)和累积超时控制(防止慢速攻击) * 每个IP连接数 限制 * 全局最大连接数限制 * 最大单个文件缓存大小 选择hetao的理由: *在Linux上的综合性能约比Nginx还要快三倍,尤其适合中小型静 态文件 * hetao是众多开源Web服务器中在WINDOWS版本唯一全部采用IOCP模型。Apache的WINDOWS版本是传统的Leader-Follow多进程模型,Nginx则 是多线程select模型(玩具?) * 配置文件采用JSON标准格式,简洁易写,而且支持行注释和块注释。Apache配置格式比较复杂,Nginx配置 格式多变怪异且不支持块注释 *
看门狗程序是一种常见的守护进程,主要用于监测系统进程是否正常运行,当进程出现异常或崩溃时,看门狗程序会自动重启该进程,确保系统的稳定性和可靠性。 下面是一个利用进程子进程实现看门狗程序的 C 语言实现示例: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> #include <sys/wait.h> pid_t pid = 0; void sighandler(int signum) { printf("Child process %d has died.\n", pid); pid = 0; } int main(int argc, char *argv[]) { signal(SIGCHLD, sighandler); while(1) { if(pid == 0) { pid = fork(); if(pid == 0) { // 子进程 execlp("your_program", "your_program", NULL); exit(0); } else if(pid > 0) { // 进程 printf("Child process %d has been started.\n", pid); } else { // 出错处理 printf("Failed to fork.\n"); exit(1); } } sleep(5); } return 0; } ``` 该程序的实现逻辑如下: 1. 程序开始运行时,先设置一个信号处理函数 `sighandler`,用于捕获子进程异常退出的信号 `SIGCHLD`。 2. 进入无限循环,不断检测子进程是否存在。如果子进程不存在,则创建一个新的子进程并启动它;如果子进程已经存在,则继续等待。 3. 在创建子进程时,进程会调用 `fork()` 函数创建一个新的进程子进程会使用 `execlp()` 函数执行 `your_program` 程序,如果执行成功则直接退出。 4. 在进程中,如果 `fork()` 函数返回的结果大于 0,则表示子进程创建成功,此时输出一条提示信息,并且保存子进程进程 ID;如果 `fork()` 函数返回的结果小于 0,则表示创建子进程失败,此时输出一条错误信息并退出。 5. 如果在运行的过程中,子进程异常退出,则会触发 `SIGCHLD` 信号,此时会调用 `sighandler()` 函数,输出一条提示信息,并将子进程 ID 置为 0,以便下次重新创建子进程。 6. 循环执行直到程序结束。 注意:上述示例中的 `your_program` 应该替换成你自己的程序名,该程序应该是一个需要被监控的进程。另外,该程序还需要添加一些异常处理的代码,以便在运行过程中出现异常时能够及时发现和修复问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值