Linux网络编程3——多进/线程并发服务器

2023-05-16

视频链接

黑马程序员-Linux网络编程_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1iJ411S7UA?p=37

目录

一、高并发服务器

1.1 图示

1.2 分类

二、多进程并发服务器

2.1 回顾前面的内容

2.2 步骤

2.3 多进程并发服务器实现

三、多线程并发服务器

3.1 步骤

3.2 多线程并发服务器实现


一、高并发服务器

1.1 图示

1.2 分类

多进程并发服务器

多线程并发服务器

二、多进程并发服务器

2.1 回顾前面的内容

服务端创建一个套接字 lfd,用来建立连接。客户端有连接请求的时候,借助 lfd 创建一个 cfd 套接字,客户端跟客户端 cfd 建立连接。再来一个客户端是和新创建的 cfd2 建立连接,所以 lfd 就一直处于空闲状态,等待其他客户端过来建立连接

多进程中 cfd 就是子进程的角色,lfd 就是父进程的角色

2.2 步骤

第1步:创建监听套接字 lfd,使用函数 Socket();

第2步:绑定地址结构 Struct scokaddr_in addr;,使用函数 Bind();

第3步:让套接字进入监听状态并响应客户端请求,使用函数 Listen();

第4步:

while(1) {
        cfd = Accpet();  // 接受客户端连接请求
        pid = fork();      // 创建子进程
        if(pid == 0) {     // 子进程执行的操作
                close(lfd); // 关闭用于建立连接的套接字 lfd(这是父进程的任务)
                read();      // 从套接字中读取客户端发来的消息
                小写字母转换成大写字母();
                write();      // 写入用于通信的套接字中
        } else if (pid > 0) {  // 父进程
                close(cfd);  // 关闭用于客户端通信的套接字
                while(1) {  //等待子进程
                        waitpid(0, NULL, 0);  // 在这里循环调用不阻塞回收子进程会存在问题,所以后面写在回调函数中了
                }
                contiue;
        }
}

2.3 多进程并发服务器实现

#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<string.h>
#include<strings.h>
#include<unistd.h>
#include<errno.h>
#include<signal.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<pthread.h>

#include"wrap.h"

#define SRV_PORT 9999

void perr_exit(const char *s)
{
	perror(s);
	exit(1);
}

int main(int argc, char *argv[])
{
	int lfd, cfd;
	pid_t pid;
	struct sockaddr_in srv_addr, clt_addr;
	socklen_t clt_addr_len;
	char buf[BUFSIZ];
	int ret, i;
	// 将地址结构清零	
	// 第一种方法: 
	// memset(&srv_addr, 0, sizeof(srv_addr));
	// 第二种方法:
	bzero(&srv_addr, sizeof(srv_addr));

	srv_addr.sin_family = AF_INET;
	srv_addr.sin_port = htons(SRV_PORT);
	srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	lfd = socket(AF_INET, SOCK_STREAM, 0);

	bind(lfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));

	listen(lfd, 128);
	clt_addr_len = sizeof(clt_addr);

	while (1) {
		cfd = accept(lfd, (struct sockaddr *)&clt_addr, &clt_addr_len);
		
		pid = fork();
		
		if (pid < 0) {
			perr_exit("fork error");
		} 
		else if (pid == 0) {
			close(lfd);
			break;
		}
		else {
			close(cfd);
			continue;
		}
	}
	
	// 子进程执行的操作
	if (pid == 0) {
		while(1) {
			ret = read(cfd, buf, sizeof(buf));
			if (ret == 0) {
				close(cfd);
				exit(1);
			}	
			for (i = 0; i < ret; i++) {
				buf[i] = toupper(buf[i]);
			}	
			write(cfd, buf, ret);
			write(STDOUT_FILENO, buf, ret);
		}
	}

	return 0;
}

因为没回收子进程,所以有很多僵尸进程

增加信号触发用于回收的函数

#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<string.h>
#include<strings.h>
#include<unistd.h>
#include<errno.h>
#include<signal.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<pthread.h>

#include"wrap.h"

#define SRV_PORT 9999

void perr_exit(const char *s)
{
	perror(s);
	exit(1);
}

void catch_child(int signum)
{
	while (waitpid(0, NULL, WNOHANG) > 0);
	return ;
}

int main(int argc, char *argv[])
{
	int lfd, cfd;
	pid_t pid;
	struct sockaddr_in srv_addr, clt_addr;
	socklen_t clt_addr_len;
	char buf[BUFSIZ];
	int ret, i;
	// 将地址结构清零	
	// 第一种方法: 
	// memset(&srv_addr, 0, sizeof(srv_addr));
	// 第二种方法:
	bzero(&srv_addr, sizeof(srv_addr));

	srv_addr.sin_family = AF_INET;
	srv_addr.sin_port = htons(SRV_PORT);
	srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	lfd = socket(AF_INET, SOCK_STREAM, 0);

	bind(lfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));

	listen(lfd, 128);
	clt_addr_len = sizeof(clt_addr);

	while (1) {
		cfd = accept(lfd, (struct sockaddr *)&clt_addr, &clt_addr_len);
		
		pid = fork();
		
		if (pid < 0) {
			perr_exit("fork error");
		} 
		else if (pid == 0) {
			struct sigaction act;
			act.sa_handler = catch_child;
			sigemptyset(&act.sa_mask);
			act.sa_flags = 0;

			ret = sigaction(SIGCHLD, &act, NULL);
			if (ret != 0) {
				perr_exit("sigaction error");
			}
			close(lfd);
			break;
		}
		else {
			close(cfd);
			continue;
		}
	}
	
	// 子进程执行的操作
	if (pid == 0) {
		while(1) {
			ret = read(cfd, buf, sizeof(buf));
			if (ret == 0) {
				close(cfd);
				exit(1);
			}	
			for (i = 0; i < ret; i++) {
				buf[i] = toupper(buf[i]);
			}	
			write(cfd, buf, ret);
			write(STDOUT_FILENO, buf, ret);
		}
	}

	return 0;
}

三、多线程并发服务器

3.1 步骤

第1步:创建监听套接字 lfd,使用函数 Socket();

第2步:绑定地址结构 Struct scokaddr_in addr;,使用函数 Bind();

第3步:让套接字进入监听状态并响应客户端请求,使用函数 Listen();

第4步:

while(1) {
        cfd = Accpet(lfd);       // 接受客户端连接请求
        pthread_create(&tid, NULL, tfn, NULL);  // 创建子线程
        pthread_detach(tid);  // 前面是线程分离的函数,如果想接受子线程的返回值,需要 pthread_join(tid, void **); 这个函数,但是这个函数是阻塞等待的。我们可以创建一个新的线程专门用于回收这个子线程
}

第5步:

void *tfn(void *arg)
{
        close(lfd);
        read(cfd);
        小 -> 大
        write(cfd);
        pthread_exit((void*)10);
}

3.2 多线程并发服务器实现

#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define MAXLINE 8192
#define SERV_PORT 8000

struct s_info {  // 定义一个结构体, 将地址结构跟cfd捆绑  
	struct sockaddr_in cliaddr;
	int connfd;
};

void *do_work(void *arg)
{
	int n,i;
	struct s_info *ts = (struct s_info*)arg;
	char buf[MAXLINE];
	char str[INET_ADDRSTRLEN];	// #define INET_ADDRSTRLEN 16  可用"[+d"查看  

	while (1) {
		n = read(ts->connfd, buf, MAXLINE);  // 读客户端  
		if (n == 0) {
			printf("the client %d closed...\n", ts->connfd);
			break;  // 跳出循环,关闭cfd  
		}
		printf("received from %s at PORT %d\n",
				inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
				ntohs((*ts).cliaddr.sin_port));	 // 打印客户端信息(IP/PORT)  
		for (i = 0; i < n; i++)
			buf[i] = toupper(buf[i]);  // 小写-->大写  
		write(STDOUT_FILENO, buf, n);  // 写出至屏幕  
		write(ts->connfd, buf, n);     // 回写给客户端  
	}
	close(ts->connfd);
	
	return (void *)0;
}

int main(void)
{
	struct sockaddr_in servaddr, cliaddr;
	socklen_t cliaddr_len;
	int listenfd, connfd;
	pthread_t tid;

	struct s_info ts[256];  // 创建结构体数组  
	int i = 0;

	listenfd = socket(AF_INET, SOCK_STREAM, 0);  // 创建一个socket, 得到lfd  

	bzero(&servaddr, sizeof(servaddr));  // 地址结构清零  
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  // 指定本地任意IP  
	servaddr.sin_port = htons(SERV_PORT);  // 指定端口号   

	bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));  // 绑定  

	listen(listenfd, 128);  // 设置同一时刻链接服务器上限数  

	printf("Accepting client connect ...\n");

	while (1) {
		cliaddr_len = sizeof(cliaddr);
		connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);  // 阻塞监听客户端链接请求  
		ts[i].cliaddr = cliaddr;
		ts[i].connfd = connfd;
		
		pthread_create(&tid, NULL, do_work, (void*)&ts[i]);
		pthread_detach(tid);  // 子线程分离,防止僵线程产生.  
		i++;
	}

	return 0;
}

编译和运行 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux网络编程3——多进/线程并发服务器 的相关文章

  • JLINK给STM32下载的两种模式--jtag & sw连线及配置

    jtag线就不说了 xff0c 将jlink的Vref GND TMS TCK分别接至SW接口 对于STM32F103RCT6来说 xff1a TMS PA12 xff0c TCK PA14 关于KEIL MDK中的设置如下图所示就可以了
  • 3.3V过压保护电路

    好久没写了 xff0c 今天就写一些工作中用到的一个电路 3 3V过压保护电路 通常一个电路中给单片机等对电压信息敏感的器件供电时都会小心翼翼 xff0c 严防前级降压电路出问题 xff0c 我就碰到过12V转5V的1117奔溃记过加在ST
  • eagle使用注意点

    使用eagle也有快一年时间了 xff0c 刚开始很不习惯 xff0c 后来习惯了也还可以 xff0c 这里我举出几个设计中经常出错的地方 xff1a 1 PCB翻转问题 xff1a 在翻转PCB文件时一定要打开torigin borigi
  • 自制pixhawk电脑不识别com口

    在原版pix上面进行改版很方便 xff0c 可以去除很多不必要的电路 笔者将电源管理芯片去除 xff0c 5V来源于变压器输出或者是连接电脑时的USB供电 xff0c 并将它们并联起来 xff0c 但是板子做回来焊接后发现问题如下 xff1
  • eagle pcb v8.2 便捷性大大提升

    eagle pcb在被Autodesk收购之前是7 x版本 xff0c 但是却有一些一直被吐槽的东西 xff0c 说实话这些东西确实增加了布线难度 xff0c 增加了布板时间 xff1a 1 real time DRC xff1a 在7 x
  • Ubuntu firefox 显示在运行无法打开,如何在终端关闭进程

    用top命令找不到firfox的进程 xff0c 查看某个用户运行的进程 xff1a ps u username grep eclipse 查看用户名为 xff1a username 的用户是否运行了eclipse 查看用户当前运行fire
  • 【万字详解】cJSON解析

    目录 1 通过README文件 xff0c 初步了解cJSON xff1a 1 1 头文件的开头和结尾 xff1a 1 2 头文件关于cJSON类型的宏定义 1 3 头文件中的extern 2 阅读并且分析cJSON源码 2 1 结构体st
  • VINS-mono 解析 新特征

    在17 12 29 xff0c VINS更新了代码加入了新的特征 xff0c 包括map merge 地图合并 pose graph reuse 位姿图重利用 online temporal calibration function 在线时
  • VINS-mono 位姿图 重利用测试

    在前一篇博文里介绍了VINS mono pose graph reuse功能的使用 xff0c 这里接着贴出一些延伸的测试 xff0c 并进行一些探讨 延伸测试 一般来说 xff0c 加载地图是进行非GPS定位必要的一步 这里根据新的VIN
  • 2022年全国大学生电子设计大赛省赛A题

    2022年全国大学生电子设计大赛省赛A题 交流电子负载 文章目录 2022年全国大学生电子设计大赛省赛A题 交流电子负载 前言一 总体思路二 模块设计1 半桥模块2 测量模块3 辅助电源模块 三 主电路搭建总结 前言 2022年全国大学生电
  • linux下使用shell发送http请求

    一 curl 1 get请求 curl命令默认下就是使用get方式发送http请求 curl www baidu com 2 post请求 使用 d参数 xff0c 形式如下 xff1a curl d 34 param1 61 value1
  • 网络摄像头 接口协议 ONVIF,PSIA,CGI,ISAPI

    ONVIF致力于通过全球性的开放接口标准来推进网络视频在安防市场的应用 xff0c 这一接口标准将确保不同厂商生产的网络视频产品具有互通性 2008年11月 xff0c 论坛正式发布了ONVIF第一版规范 ONVIF核心规范1 0 随着视频
  • VLC架构及流程分析

    注明 xff1a 此文为转载 原文地址 xff1a https jiya io archives vlc learn 2 html 由于本人之前由于在工作中需要对VLC进行二次开发 因此进行了相关工作的开发 xff08 由于工作原因 目前暂
  • 学习、使用C++开发是不是过时了?

    C 43 43 在开发过程中真心很尴尬 1 拿相同薪水使用不同语言的程序员 xff0c 开发大多数相同的常见业务需求 xff0c C 43 43 总是进度较慢 xff08 不考虑时 空复杂性及效率 xff09 2 扩展性 跨平台 资源 内存
  • strcat()函数的用法

    这几天的一次程序练习中用到了strcat 函数 xff0c 但也想到了一些问题 我们都知道strcat str ptr 是将字符串ptr内容连接到字符串str后 xff0c 然后得到一个组合后的字符串str xff0c 比如 str字符串内
  • libQtCore.so.4 undefined symbol :g_main_context_push_thread_default

    开发板终端执行qt程序 qtDemo qws 报错 xff1a libQtCore so 4 undefined symbol g main context push thread default 解决方案 xff1a cd DVSDK p
  • curl时设置Expect的必要性

    curl 在项目中使用频率较高 xff0c 比如内部接口 第三方 api 图片存储服务等 xff0c 但是我们在使用 curl 时可能并没有注意到 Expect 这个请求头信息 xff0c 而 Expect 设置不正确 xff0c 会导致不
  • 奇偶校验原理

    奇校验 xff1a 求一个字节8位中 1 的个数 xff0c 添加一位校验位 xff0c 使9位中 1 的个数为奇数 xff1b 偶校验同理 奇校验就是让原有数据序列中 xff08 和要加上的一位 xff09 1的个数为奇数 如010001
  • CreateMutex函数函数用来实现进程互斥

    CreateMutex函数 正常情况下 xff0c 一个进程的运行一般是不会影响到其他正在运行的进程的 但是对于某些有特殊要求的如以独占方式使用串行口等硬件设备的程序就要求在其进程运行期间不允许其他试图使用此端口设备的程序运行的 xff0c
  • C++与QML交互总结

    一直对于QT的理解和使用都停留在主窗口程序和控制台程序 xff0c 虽然QT的新东西QML听过也接触过 xff0c 但是基本上没梳理过调用流程 趁着旧项目要使用QML技术 xff0c 现在就将C 43 43 和QML交互进行总结 目录 一

随机推荐

  • QT下TCP协议实现数据网络传输

    QT开发框架以其跨平台的优势 xff0c 在全世界IT界如雷贯耳 其封装了功能齐全的各种类 xff0c 大大的提高了开发者的效率 本篇内容将介绍如何使用QT 6 4 1框架开发服务器和客户端程序 xff0c 让两端能够首发消息 xff0c
  • 从零实现vins-mono+fast-planner+M100无人机实验在现实场景中的应用

    版权声明 本文为博主原创文章 未经博主允许不能随意转载 本文链接 https blog csdn net AnChenliang 1002 article details 109535355 最近由于科研的需要 要将VINS mono与fa
  • Linux下C语言实现HTTP文件服务器和TCP协议实现网络数据传输

    在实际开发中经常用到web框架 xff0c 比如Servlet xff0c SpringBoot等 xff0c 这些开发框架提高了我们的开发效率 xff0c 节省了开发时间 但是这会令我们技术人员处于浮云之上 xff0c 看不到其本质 说实
  • Linux下C语言UDP协议通信实践

    UDP和TCP协议一样 xff0c 都是传输层协议 是无连接的 xff0c 不安全的 xff0c 报式传输层协议 xff0c 通信过程默认也是阻塞的 其通信特点主要如下 xff1a xff08 1 xff09 不需要建立连接 xff0c 所
  • Ubuntu下PyQt5使用总结

    因为工作中需要给交付团队开发桌面工具 xff0c 考虑到交付团队多使用Mac xff0c 调研了一下发现PyQt5可以实现跨平台 xff0c 满足工具开发需要 xff0c 就用其开发了桌面工具 现以ubuntu开发环境为例总结一下开发过程
  • ubuntu下安装配置grpc

    目录 1 准备环境 2 安装protobuf 3 安装cares库 3 安装grpc 1 17 x 1 准备环境 sudo apt get install pkg config sudo apt get install autoconf a
  • cmake管理子程序,lib库和so库应用实践

    cmake在管理大型项目时经常被用到 xff0c 本文以简单程序演示来说明camke管理项目应用 xff0c 其中包括主程序 xff0c 子程序 xff0c so库程序 xff0c lib程序 目录 1 程序目录结构 2 编译执行 3 清除
  • GIt常用命令总结

    目录 1 创建新建分支 2 强制拉去代码 3 合并相邻提交 xff0c 保证只有一个commit信息 4 本地回退 5 查看git修改列表 6 提交代码 7 切换新分支并从服务端拉取最新 8 git cherry pick合并代码使用 9
  • Linux 下I/O多路复用总结

    xfeff xfeff select xff0c poll xff0c epoll都是IO多路复用的机制 I O多路复用就通过一种机制 xff0c 可以监视多个描述符 xff0c 一旦某个描述符就绪 xff08 一般是读就绪或者写就绪 xf
  • WAV文件头分析

    WAV语音文件头部含有44字节的标志信息 xff0c 其含义如下 xff1a ckid xff1a 4字节 RIFF 标志 xff0c 大写 wavHeader 0 61 39 R 39 wavHeader 1 61 39 I 39 wav
  • Linux环境下限制网速和取消限制网速

    查看网卡信息 ip addr root 64 rabbitmq01 ip addr 1 lo lt LOOPBACK UP LOWER UP gt mtu 65536 qdisc noqueue state UNKNOWN qlen 1 l
  • Linux 网络编程2 TCP并发服务器

    Linux 网络编程学习 TCP IP网络编程2 TCP多线程服务器TCP多进程服务器 在前面TCP网络编程代码的基础上进行改造 xff0c 实现并发服务器功能 TCP多线程服务器 实现功能 xff1a server端可以绑定在任意IP端s
  • HTTP Digest authentication

    什么是摘要认证 摘要认证 xff08 Digest authentication xff09 是一个简单的认证机制 xff0c 最初是为HTTP协议开发的 xff0c 因而也常叫做HTTP摘要 xff0c 在RFC2617中描述 其身份验证
  • 简单的netfilter hook函数注册以及内核链表的使用

    include lt linux netfilter h gt include lt linux init h gt include lt linux module h gt include lt linux netfilter ipv4
  • 详述GPS原理及RTK技术应用

    完整的PPT文档在这里 xff1a 详述GPS原理及RTK技术应用 1 GPS概述 1 1定义 全球定位系统GPS xff08 Global Position System xff09 xff0c 全称为NAVSTAR GPS xff08
  • PHP HTTP Digest校验

    PHP作为客户端进行HTTP Digest校验 span class token comment 请求方法 span span class token variable username span span class token oper
  • Http Digest认证协议

    其认证的基本框架为挑战认证的结构 xff0c 如下图所示 xff1a xfeff xfeff 1 客户端希望取到服务器上的某个资源 xff0c 向服务器发送Get请求 2 服务器收到客户端的请求后 xff0c 发现这个资源需要认证信息 xf
  • Postman 安装

    Postman 的下载安装 Postman是一个用于构建和使用API的API平台 xff08 接口的调试工具 xff09 选择对应的系统和版本进行下载 https github com hlmd Postman cn 这里我的电脑是wind
  • 【安卓自定义控件系列】自绘控件打造界面超炫功能超强的圆形进度条

    在前面我们讲过了安卓自定义控件三种方式中的组合控件 xff0c 现在我们来讲解一下通过自绘的方式来实现自定义控件 xff0c 本博客将以自定义圆形进度条为例向大家讲解自定义控件的知识 xff0c 首先来看一下效果图吧 xff0c 这个是本人
  • Linux网络编程3——多进/线程并发服务器

    视频链接 黑马程序员 Linux网络编程 哔哩哔哩 bilibili https www bilibili com video BV1iJ411S7UA p 61 37 目录 一 高并发服务器 1 1 图示 1 2 分类 二 多进程并发服务