UNIX Socket网络编程:自己动手实现并发 http 服务器

golang中基于http 和unix socket的通信代码实现(服务端基于gin框架) 目录一、问题背景二、什么是unix socket三、原生的unix socket通信方式四、http+unix socket通信,服务端基于gin框架五、demo的实现移步到项目中六、结论七、后续工作 一、问题背景 实习所在公司的A、B两个应用部署在同一台机器上,之前是采用http://127.0.0.1:xxx进行调用,协议选用tcp。而对于同一台机器的进程间通信来说,tcp协议为了确保传输的可靠性带来了一些不必要的负担,因此计划用unix domain socket“取代”tcp。此外采用此种方式也方便 阅读详情

开源链接:https://github.com/ttoobne/bohttpd:

(一)整体设计:

        主循环采用多路复用,如果连接到达则集中accept,在已连接描述符上如果有就绪事件,则分配任务给线程池执行I/O操作。已连接描述符和监听描述符都设置为非阻塞。

1. 为什么用线程池?

        如果每个连接到达就 create 一个新的线程,并发量较大的情况下创建和销毁线程的开销不可忽视,并且如果创建的线程数量没有限制,将会消耗大量 CPU 资源用来切换线程。这时如果采用线程池预先分配若干个线程,那么在执行请求时消除了创建销毁线程的开销。线程数量固定,通过维护一个工作队列,有请求到达时将请求放入工作队列,每个处于空闲中的线程都可以取出任务然后执行,执行完毕又阻塞等待新的任务。

2. 为什么采用非阻塞I/O?

        网络中的状况不可预测,如果网络有延迟,表现为当前服务器读取数据还没有读到 EOF 但是接受缓冲区没有数据可读,这时线程会阻塞在 read() 上,如果设置成非阻塞,那么 read() 会返回 EAGAIN ,表示当前接受缓冲区没有数据,还需要下一次读,这时线程可以先保存状态返回去执行其他的任务,如果延迟的数据到达了就又分配给一个线程继续读取然后执行。http 持久连接时情况类似,总的来说就是如果当前描述符没有数据可读,那么不会一直阻塞而是返回先去执行其他任务。

3. 为什么 epoll 要使用边缘触发(ET)?

        如果是水平触发,那么考虑如果当前有一个线程在执行请求,读到一半的时候主循环 epoll wait 返回可读事件,这时正在执行的那个请求也会被返回,因为描述符上有数据还没读完,这时就会导致两个线程同时执行同一个请求。

4. 为什么监听描述符也设置为非阻塞?

        监听描述符上的可读事件可能包含多个连接到达,由于采用了边缘触发,则需要一次性处理完所有的连接请求,由于不能确定具体有多少连接到达,就需要一个循环来处理,那么这时最后一个 accept 就会阻塞,导致无法执行后续的可读请求。那么在设置为非阻塞之后当没有连接到达时,accept 返回 EAGAIN,退出循环继续等待新的事件到达即可。

(二)线程池的实现(threadpool)

        整个机制比较简单,预先分配若干个线程,一个工作队列。添加任务或者线程取任务用一个互斥锁和两个条件变量维持同步。每个工作线程阻塞在 nempty_cond 条件变量上,等待任务队列非空的条件成立就执行对应的任务。添加任务的工作由主循环完成,如果工作队列满,那么阻塞在 nfull_cond 条件变量上,等待任务队列非满就添加任务到任务队列。

(三)定时器(http_timer, rbtree)

        定时器用来清理超时的已连接事件,实现参考 nginx 的红黑树实现,向定时器中添加事件就是向红黑树中添加节点,删除事件就是删除节点,处理超时事件就是不断取出红黑树中的键最小的节点,如果超时就执行超时事件的回调函数。在主循环中每次取出定时器中距离最近的时间,设置为 epoll 的最长阻塞时间,如果 epoll 直到返回都没有事件到达,那么代表需要清理超时事件了,接着执行超时处理即可。由于每个请求执行开始先需要删除定时器,如果是长连接则需要继续添加定时器,而执行请求又是多线程的,那么所有对红黑树进行改动的地方都需要加锁。

        红黑树的实现较为复杂,尤其是删除操作,先类似于普通二叉搜索树那样删除节点,删除完之后还需要考虑是否失去性质,如果性质不满足那么需要进行调整。情况比较复杂,但网上有很多讲解。

(四)解析和处理 http 请求(http_request, http_parse, http)

        这个部分就是根据协议来实现就行,http_request_t 结构体保存读取到的和解析出来的请求信息,由于使用到了非阻塞I/O,有可能读取了一部分之后线程返回了,那么就需要维护一个状态来保存当前解析到了那个步骤,http_parse 就做了这个工作,实现逻辑比较简单,就是不断读取、切换状态。http_request 中解析完的请求行信息会保存在 http_request_t 结构体中,解析完的请求首部会保存在 http_header_t 中,每个首部组成一个链表,链表头在 http_request_t 中保存,解析完的准备发送的首部信息保存在 http_headers_out_t 结构体中。响应请求就是根据解析出来的信息发送指定资源或者发送错误消息。

(五)封装 EPOLL(epoll)

        把有关于 epoll 的操作都封装起来,简化调用。将返回的事件数组封装在内部,申请内存在创建 epoll 描述符的时候就完成,后续操作只需要操作 epoll_t 结构体即可。

(六)日志库(log)

        这个日志库其实是一开始就要先完成的,但是开始的时候出于方便,就随便写了几个宏定义来代替,debug也还能做,也就一直用着了。后来看之前的宏定义只有ERROR和DBG,想着还是需要一个更加完备一点的日志库,所以就实现了一个超简易日志库。定义了六个日志级别,将日志信息输出到标准错误。

(七)配置文件(config)

        支持自定义配置信息,实现了一个简单的配置文件解析,逻辑也比较简单,就是针对每行的语法进行简单分析和出错处理。配置文件的配置信息包含线程池大小、工作队列大小、持久连接的超时时间、端口号、http 主目录、默认文件,还支持以 # 开头的注释。

(八)make

        作为一个项目当然需要一个 Makefile 来方便编译,make 会根据指定的命令编译项目。用法也不难,规定要构建哪个文件、它依赖哪些源文件和头文件,当那些文件有变动时,如何重新构建它。

C语言手搓HTTP服务器:从Socket到并发模型的底层网络编程实践 HTTP协议作为Web通信的基石,其底层实现原理是每一位后端开发者必须掌握的核心知识。理解HTTP协议的工作原理,关键在于剖析其基于TCP/IP协议栈的请求-响应模型,这涉及到网络字节序、Socket编程、报文解析等底层技术。掌握这些技术不仅能提升系统调试和性能优化的能力,更是构建高并发、高性能网络服务的工程基础。通过用C语言从零实现一个支持GET请求的HTTP服务器,开发者可以深入理解从Socket创建、地址绑定、监听连接到请求解析、响应构建的完整链路,并直面内存管理、并发处理等系统级挑战。这一实践过程尤 阅读详情

相关推荐

深入学习理解UNIX网络编程

深入学习理解UNIX网络编程

snapepotter的博客 1787

通过unix socket建立http连接

除了我们熟知的tcp连接以外还可以通过本地socket建立通信,Unix Domain Socket的英文简称是UDS,就是一种常用的方式,但它只支持建立本地连接,它的好处是通过路径而非端口建立连接,好处是可以避免端口占用。 首先看服务端代码 package main import ( "fmt" "net" "net/http" "os" ) func main() { if len(os.Args) < 2 { fmt.Fprintln(os.Stderr, "usage:",

柳清风的专栏 2924

Linux C语言网络编程:从Socket到epoll的并发服务器实战

网络编程是构建分布式系统和网络应用的核心技术,其基础在于理解操作系统提供的进程间通信机制。在Linux环境下,系统调用和内核机制为网络通信提供了最直接的访问途径。其核心原理围绕Socket API展开,通过创建、绑定、监听和连接等系统调用,实现不同主机间的数据交换。这项技术的核心价值在于能够以接近硬件和操作系统内核的方式,实现对网络通信的精细控制和高性能处理,尤其适合开发需要极致性能和高并发的服务器程序,如Web服务器、实时通信服务和分布式系统节点。在实际应用中,开发者需要根据场景选择合适的并发模型,例如多

weixin_34007886的博客 700

socket网络编程——多进程、多线程处理并发

如果客户端暂时没发数据,服务端会在 recv()阻塞。此时,其他客户端向服务器发起连接后,由于服务器阻塞了,无法执行 accept()接受连接,也就是其他客户端发送的数据,服务器无法读取。服务端接受一个客户端的连接后,创建一个线程或者进程,然后在新创建的线程或进程中循环处理数据。主线程(父进程)只负责监听客户端的连接,并使用 accept()接受连接,不进行数据的处理。如下图所示, 当一个客户端与服务器建立连接以后,服务器端 accept()返回,进而准备循环接收客户端发过来的数据。

weixin_64685646的博客 2096

Socket 编程实现基于 HTTP 协议的客户和服务

目录前言研究背景及意义研究内容及方法研究要求与目标相关知识点HTTP协议TCP协议UDP协议Socket编程技术需求分析Socket编程Swing包多线程的应用功能设计功能测试总结 前言 研究背景及意义 基于Socket的网络编程技术在人们不断的研究和探索下,日益的完善与成熟,已被广泛的应用在通信、医疗等各个领域,比如市面上比较普遍的QQ、微信等以内部网络为中心的资源共享系统,都应用到了套接字网络编程技术。 在现在的网络应用中,通信双方最常见的交互模式便是Client/ Server模式,它通常采用监听/连

qq_44704426的博客 1294

QtHttpServer例子

博客地址:https://blog.youkuaiyun.com/u012020854/article/details/105537260

Qt+HttpServer的学习记录

QtWepApp是一个C++中的HTTP服务器库,其灵感来自Java Servlet。适用于Linux、Windows、Mac OS和Qt Framework支持的许多其他操作系统。

wuhao 3273

requests-unixsocket, 使用请求通过UNIX域套接字进行HTTP会话.zip

requests-unixsocket, 使用请求通过UNIX域套接字进行HTTP会话 请求 UNIXSocket 使用请求通过UNIX域套接字来讨论 HTTP用法你可以通过实例化一个特殊的Session 对象来使用它:import jsonimport requests_unixsocket

Qt httpserver 理解与使用

系统讲解了Qt http server的所有知识点和使用方法,包括路由概念,多线程使用,和如何创建https server。

MrTsai_cpp的博客 1万+

TI 实时操作系统SYS/BIOS使用总结

1:概述: SYS/BIOS 是一个可扩展的实时的操作系统。具有非常快速的响应时间(在中断和任务切换时达到较短的延迟),响应时间的确定性,强壮的抢占系统,优化的内存分配和堆栈管理(尽量少的消耗和碎片)。能够实现系统的模块化并可裁剪。 最大的特点就是:实时。 2:XDCtools: XDCtools 是SYS/BIOS引用的一种实时的软件组件技术(RTSC),它包括一些有用的工具,标准的AP

带头奋青的博客 5万+

昇腾910安装驱动出错,降低Centos7.6的内核版本

Centos7.6 启动内核修改,解决昇腾910安装驱动错误的问题。

深蓝 3300

Unix网络编程学习笔记

unix网络编程,C语言,多线程,多进程,epoll,select

weixin_45045804的博客 2630

YOLOv11 | 一文带你深入理解ultralytics最新作品yolov11的创新 | 训练、推理、验证、导出 (附网络结构图)

ultralytics发布了最新的作品YOLOv11,这一次YOLOv11的变化相对于ultralytics公司的上一代作品YOLOv8变化还是很大的(YOLOv9、YOLOv10均不是ultralytics公司作品),其中改变的位置涉及到C2f变为C3K2,在SPPF后面加了一层类似于注意力机制的C2PSA,还有一个变化大家从yaml文件是看不出来的就是它的检测头内部替换了两个DWConv,在损失函数方面就没有变化了还是采用的CIoU作为边界框回归损失,下面带大家深入理解一下ultralytics最新作品

Snu77的博客 18万+

Socket网络编程基础与HTTP协议实现

Socket作为网络编程的核心抽象层,通过封装TCP/IP协议栈提供类文件操作接口,是构建网络应用的基石。其双向通信特性支持数据同时收发,而家族类型(AF_INET/AF_INET6)和传输类型(SOCK_STREAM/SOCK_DGRAM)的参数选择直接影响通信模式。理解Socket工作原理后,可进一步掌握HTTP等应用层协议的本质——它们实质是通过Socket传输的格式化文本。在物联网和Web开发场景中,深入Socket层能解决自定义协议、性能调优等关键问题。现代Python生态通过asyncio和Re

weixin_34248023的博客 436

特别章节-0.1 SolidWorks导出机械臂的URDF模型各个关节坐标系设置

通过Solidworks导出机械臂的URDF模型文件,建立机械臂的各个关节坐标系的规则以及注意点,详细步骤

六眼飞鱼的博客 1万+

【XAI】透视深度学习:CNN与Transformer的可解释性方法

深度学习模型的可解释性方法解析:本文探讨了CNN和Transformer两类主流模型的可解释性技术。针对CNN,介绍了显著性图、类激活图(CAM/Grad-CAM)和基于扰动的方法,通过可视化重要像素区域揭示决策依据。对于Transformer,重点分析了注意力机制可视化及其在文本处理中的应用,并介绍了积分梯度等归因方法。文章包含详细的Python实现示例(使用Captum库),涵盖从MNIST图像显著性分析到BERT文本注意力可视化,为初学者提供了可操作的技术指南。这些方法有助于增强模型透明度,提升AI系

u012133341的博客 382

UNIX网络编程笔记:基本TCP套接字编程

所有客户和服务器都从调用socket开始,它返回一个套接字描述符。客户随后调用connect,服务器则调用bind、listen和accept。套接字通常使用标准的close函数关闭,不过我们将看到使用shutdown函数关闭套接字的另一种方法,我们还要查看SO_LINGER套接字选项对于关闭套接字的影响。大多数TCP服务器是并发的,它们为每个待处理的客户连接调用fork派生一个子进程。我们将看到,大多数UDP服务器却是迭代的。

梅见十柒的博客 1614

笔试题-2023-思特威-数字电路设计(CIS)【纯净题目版】

10 笔试题-2023-思特威-数字电路设计(CIS)【纯净题目版】

w0shishabi的博客 1472

Python Socket 网络编程

Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页、QQ 聊天、收发 email 等等。要解决网络上两台主机之间的进程通信问题,首先要唯一标识该进程,在 TCP/IP 网络协议中,就是通过 (IP地址,协议,端口号) 三元组来标识进程的,解决了进程标识问题,

huayucong的博客 1万+

潜望式长焦模组全解析:结构构造、光路设计与工程实战挑战

随着移动影像能力的不断进化,潜望式长焦模组成为旗舰手机实现 5x 甚至 10x 光学变焦的关键配置。相比传统横向堆叠镜组,潜望式结构通过反射棱镜实现纵向空间上的光路折叠,有效解决了模组厚度与变焦行程的矛盾问题。然而,高倍变焦模组不仅面临复杂的光学路径设计,还涉及反射损耗控制、防抖马达配合、模组热应力管控与 ISP 畸变校正等一系列工程难点。本文将结合主流机型的实战经验,深入解析潜望式长焦模组的结构构造与调试路径,为影像系统工程师提供完整的实战参考。

努力分享一些人工智能、计算机视觉、影像等相关的知识干货! 3138

LPDDR6与LPDDR5 ZQ Calibration技术探讨

LPDDR6与LPDDR5 ZQ Calibration技术探讨

zilan23的博客 1099

socket unix domain socket

进程间通信有几种稳定、有效的的方式几乎被所有的操作系统采用:共享内存(Shared Memory)、管道(Pipe)、Unix Domain Socket和 RPC(Remote Procedure Calls 远程调用),本文主要介绍UDS和RPC. Socket和HTTP的区别? Socket是一个针对TCP和UDP编程的接口,你可以借助它建立TCP连接等等。而TCP和UDP协议属于传输层...

climbs的专栏 725

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Linux/UNIX系统编程手册笔记:SOCKET

Socket 是网络通信的核心接口,支持 TCP/UDP 协议,实现跨主机进程通信。创建 Socket 需指定地址族(AF_INET/IPv4)和类型(SOCK_STREAM/TCP)。服务器通过 bind() 绑定地址,listen() 监听连接,accept() 接受客户端请求。客户端用 connect() 发起连接,通过 send()/recv() 传输数据。UDP 使用 sendto()/recvfrom() 进行无连接通信。Socket 编程需注意字节序转换(htons)和地址结构转换(socka

梅见十柒的博客 1143

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

套接字编程实战:基于UNIX网络编程第3版实现一个简易HTTP/1.0服务器

本文详细介绍了如何基于UNIX套接字编程实现一个简易HTTP/1.0服务器,涵盖从socket创建到I/O复用的完整开发流程。通过解析HTTP请求、处理静态文件服务及实现并发连接等核心功能,帮助开发者深入理解网络通信本质。文章特别强调了套接字API的使用细节和性能优化技巧,适合网络编程初学者和进阶开发者。

weixin_34262482的博客 507

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

PYTHON 网络编程

Socket 编程实战 文章目录 Socket库 0.1. 什么是 Socket? 0.2. socket()函数 0.3. Socket 对象(内建)方法 0.4. 简单实例 0.5. Python Internet 模块 概述 Python socket API 2.1. TCP socket 2.2. UDP socket 常见陷阱 3.1. 忽略返回值 3.2. 误认为 TCP 具有 f...

戈扬的博客 1万+
上一篇: POJ1742 Coins (可行性背包)
下一篇: Linux云主机部署搭建minecraft服务器以及记录java内存溢出问题
ttoobne
博客等级 码龄9年 13粉丝 59原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值