C++ Webserver从零开始:基础知识(一)——Linux网络编程基础API
目录
前言
一.socket地址API
1.主机字节序和网络字节序
2.通用socket地址
3.专用socket地址
二.创建socket
三.绑定socket(命名socket)
四.监听socket
五.接受连接(服务端)
六.发起连接(客户端)
七.关闭连接
八.数据读写
九.一些废话
前言
本专栏将从零开始制作一个C++ Webserver,用以记录笔者学习的过程
如果你想要跟着我这个专栏制作一个C++ Webserver,你需要掌握以下前置基础课程知识:
1.C/C++的语法(在Leetcode刷100~200题的程度即可)
2.计算机网络基础知识
3.操作系统基础知识
掌握以上前置课程知识后,即可开始本专栏的内容
一.socket地址API
1.主机字节序和网络字节序
我们知道,一个32位计算机的CPU累加器一次能累加4字节的数据,而这4字节的数据在内存中排列的顺序是可以有2种方式的,即大端字节序和小端字节序
大端字节序:一个整数的高位字节(23~31bit)存储在内存的低地址处
小端字节序:一个整数的低位字节(0 ~ 7 bit)存储在内存的低地址处
由于不同的主机使用的字节序可能不同,因此两个主机之间发送数据可能会发生错误。解决方法是:
人们制定一个规范:发送端统一使用大端字节序(因此大端字节序称为网络字节序)
而因为现代PC大多采用小端字节序,因此小端字节序称为主机字节序
Linux中实现主机字节序和网络字节序的函数:
#include<netinet/in.h>
unsigned long int htonl(unsigned long int hostlong);
unsigned short int htons(unsigned short int hostshort);
unsigned long int ntohl(unsigned long int netlong);
unsigned short int ntohs(unsigned short int netshort);
他们的作用可以通过名字理解,比如 htonl :" host to network long" ,即长整型的主机字节序转换成网络字节序。这四个函数中long类型的函数一般用来转换IP地址,short类型的一般用来转换端口号(操作系统基础知识)。
2.通用socket地址
主机之间的通信需要知晓对方的地址,而网络中主机的地址是TCP/IP协议族来定义的(计算机网络基础知识),在Linux网络编程中,我们通过使用socket的这个套接字来进行网络通信。socket定义了一系列的API实现网络通信,是非常方便好用的工具。
在socket网络编程中表示地址的是结构体sockaddr,但由于这个结构体的设计问题,无法容纳多数协议族的地址值,因此Linux定义了一个新的通用socket地址结构体
#include<bits/socket.h>
struct sockaddr_storge
{sa_family_t sa_family;unsigned long int __ss_align;char__ss_padding[128-sizeof(__ss_align)];
}
3.专用socket地址
以上两种通用socket地址其实并不好用,所以Linux为各个协议族提供了专门的socket地址结构体
其中,UNIX本地协议族使用sockaddr_un,本文不予说明
而TCP/IP协议族使用sockaddr_in和sockaddr_in6两个分别对应IPv4和IPv6
但需要注意的是,使用sockaddr_in或其他专用socket地址(包括socket_storge),最后都要强制转换成通用socket地址类型sockaddr,这是因为所有socket编程接口使用的地址参数的类型都是sockaddr
二.创建socket
我们了解socket地址API后,要如何创建一个socket呢?下面是创建socket的代码
#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain,int type, int protocol);
int socket(int domain,int type,int protocol);
- 功能:创建一个套接字
- 参数:
- domain:协议族
- AF_INET:IPv4
- AF_INET6:IPv6
- AF_UNIX,AF_LOCAL:本地套接字通信
- type:通信过程中使用的协议类型
- SOCK_STEAM:流式协议(传输层使用TCP协议)
- SOCK_DGRAM:报式协议(传输层使用UDP协议)
- protoco:具体的一个协议,写 0 就行
- 返回值:返回文件描述符,操作内核缓冲区
- 失败:-1
以上块引用中,在写Webserver时都是用笔者加粗部分的参数
另外:
type参数中还可以与以下两个参数相与计算:
SOCK_NONBLOCK:创建的socket为非阻塞
SOCK_CLOEXEC:用fork调用创建子进程时,在子进程中关闭该socket
三.绑定socket(命名socket)
在创建socket时,我们在第一个参数时给它指定了协议族,但是并未指定使用协议族中哪个具体的socket地址。所以我们用系统调用bind来给socket绑定地址。
PS:服务端需要绑定,客户端不需要绑定,客户端采用匿名绑定,操作系统会代劳。
#include<sys/types.h>
#include<sys/socket.h>
int bind(int sockfd,const struct sockaddr* my_addr,socklen_t addrlen);
- 功能:将my_addr所指的socket地址分配给未命名的socket文件描述符
- 参数
- sockfd:通过socket函数得到文件描述符
- addr:需要绑定的socket地址,这个地址封装了ip和端口号的信息
- addrlen:第二个参数结构体占的内存大小
- 返回值
- 0:成功
- -1:失败
四.监听socket
现在我们创建好了socket,也为其分配好了socket地址,接下它就可以工作进行主机间的通信了吗?其实并不行,我们还需要为他创建一个监听队列,用以存储待处理的客户连接。
以下是创建监听队列的系统调用
#include<sys/socket.h>
int lsiten(int sockfd,int backlog);
int listen(int sockfd,int backlog);
- 功能:监听socket上的连接
- 参数
- sockfd:通过socket()函数得到文件描述符
- backlog:未连接的和已经连接的和的最大值
- 返回值:
- 成功:0
- 失败:-1
五.接受连接(服务端)
现在我们已经有了一个监听socket(执行过listen调用,处于LISTEN状态的socket),我们终于可以进行通信啦!而最后一步,就是将监听队列中的一个socket取出来,即可与远端的主机进行读写交互了
下面是从监听队列取出socket的系统调用
#include<sys/types.h>
#include<sys/socket.h>
int accept(int sockfd, struct sockaddr* addr,socklen_t* addrlen);
- 功能:接受客户端连接,默认时一个阻塞的函数,阻塞等待客户端连接
- 参数
- sockfd:用于监听的文件描述符
- addr:传出参数,记录连接成功后客户端的地址信息
- addrlen:指定第二个参数的对应的内存大小
- 返回值:
- 成功:返回用于通信的文件描述符
- 失败:-1
六.发起连接(客户端)
注意,上文的绑定socket,监听socket和接受连接都是服务端要干的事,接下来讲客户端的任务。在服务端创建好了监听队列后,就可以接受来自客户端的连接请求,那么客户端是怎么发起连接请求的呢?
#include<sys/types.h>
#include<sys/socket.h>
int connect(int sockfd,const struct sockaddr* serv_addr,socklen_t addr_len);
- 功能:客户端连接服务器
- 参数
- sockfd:用于通信的文件描述符
- serv_addr:客户端要连接的服务器地址信息
- addrlen:指定第二个参数的对应的内存大小
- 返回值:
- 成功:0
- 失败:-1
七.关闭连接
通信完成后,如要关闭连接,可以通过下面的系统调用
#include<unistd.h>
int close(int fd);
fd参数是待关闭的socket,close系统调用不会立刻关闭一个连接,而是将fd的引用计数-1,只有当其引用计数为0时才会真正关闭连接(类似C++的智能指针)。
在多进程程序中,一次fork系统调用默认将引用计数+1.
如果你非要立即终止连接,也有办法,即shutdown系统调用,读者可以自行搜索。
八.数据读写
我们在二到七的过程中完整经历了socket通信的创建,命名,监听,接受(发起),关闭的过程,在连接建立成功到关闭连接的这个时间段中我们就可以进行两个主机之间的通信。
通信的方式即:
1.发送信息
2.接受信息
专业的说法也就是数据读写。Linux本身对文件的读写也可以用于socket,因为socket本身也是文件(Linux中万物皆文件)。但socket还是提供了几种好用的数据读写系统调用。
分别有
1.TCP数据读写
2.UDP数据读写
3.通用数据读写
本文只介绍TCP数据读写,UDP和通用数据读写请读者自行学习
#include<sys/types.h>
#include<sys/socket.h>
ssize_t recv(int sockfd,void* buf,size_t len,int flags);
ssize_t send(int sockfd,const void* buf,size_t len,int flags);
- 功能:数据读写
- 参数:
- sockfd:用于通信的文件描述符
- buf: 缓冲区的位置
- len:缓冲区的大小
- flags:通常取0,其他含义自行搜素,可以进行具体的控制
- 返回值:
- 成功:
- recv:返回实际读到的数据的长度,如果小于期望长度len就多调用几次recv
- send:实际写入的数据长度
- 失败:-1
九.一些废话
前面一到八即Linux网络编程基础API的常用内容了,其他的一些不常用的API如地址信息函数,socket选项等没有写入文中,一是因为其使用场景较少,二是我对这个专栏的定位是:
简洁且重要
我写的内容基本上是完成C++ Webserver所必须掌握的前置知识,所以会极可能的少,这样的话对一些没有基础却又无从下手的后辈能起到一个引入门的作用。
等真正地了解了这些内容后,再去提升应该会容易的多。之所以这也想是因为我在学习完C/C++,操作系统,计算机网络之后进行项目制作时发现根本无从下手,我在网上找到的内容很少有建立在你完全不了解任何Webserver的知识,但又学完了基础课程的情况下。所以我希望能写一些内容,对和我一样的同学有些帮助。
另外就是我也是在学习过程中,所以想记录一下学习过程帮自己更好地完成这个目标。如果本文有什么问题,或者你有什么建议的话欢迎私信笔者,我看到了应该都会回复。
相关文章:

C++ Webserver从零开始:基础知识(一)——Linux网络编程基础API
目录 前言 一.socket地址API 1.主机字节序和网络字节序 2.通用socket地址 3.专用socket地址 二.创建socket 三.绑定socket(命名socket) 四.监听socket 五.接受连接(服务端) 六.发起连接(客户端) 七.关闭连接…...

cookie和session的工作过程和作用:弥补http无状态的不足
cookie是客户端浏览器保存服务端数据的一种机制。当通过浏览器去访问服务端时,服务端可以把状态数据以key-value的形式写入到cookie中,存储到浏览器。浏览器下次去服务服务端时,就可以把这些状态数据携带给服务器端,服务器端可以根…...

【蓝桥杯选拔赛真题30】C++字母转换 第十三届蓝桥杯青少年创意编程大赛C++编程选拔赛真题解析
目录 C/C++字母转换 一、题目要求 1、编程实现 2、输入输出...
资产负债表#通俗易懂
资产负债表(the Balance Sheet)亦称财务状况表,表示企业在一定日期(通常为各会计期末)的财务状况(即资产、负债和业主权益的状况)的主要会计报表。 (99 封私信 / 11 条消息) 能通俗易懂的给小白…...
PCF8563转STM32 RTC避坑指南
问题一,时间读取错误 原因,读写时间必须Time在前,Date在后 HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BCD); HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BCD); HAL_RTC_SetTime(&hrtc, &time, RTC_FORMAT_BCD); …...

前端重置密码报错记录
昨天晚上,我写了重置密码的前端,测试的时候报错 今天上午,我继续试图解决这个问题,我仔细检查了一遍,前端没有问题 可以正常接收输入的数据并且提交 但是后端接收到的数据为空,后端接口也没有问题 但后端收…...
css3的过度效果transition支持哪些属性,Transition 所支持的css属性
transition-property是用来指定当元素其中一个属性改变时执行transition效果: 所支持的属性类型如下: 名称描述属性color: 通过红、绿、蓝和透明度组件变换(每个数值处理) 如: background-color, border-color, color, outline-co…...

JAVAEE初阶 文件IO(一)
这里写目录标题 一. 计算机中存储数据的设备1.1 CPU1.2 内存1.3 硬盘1.4 三种存储的区别 二.文件系统2.1 相对路径2.2 绝对路径2.3 .和..的含义2.4 例子2.5 everything工具 三.文件3.1 文本文件3.2 二进制文件 四. JAVA对于文件的API4.1 getParent getName getPath getAbsolute…...

使用WAF防御网络上的隐蔽威胁之CSRF攻击
在网络安全领域,除了常见的XSS(跨站脚本)攻击外,CSRF(跨站请求伪造)攻击也是一种常见且危险的威胁。这种攻击利用用户已经验证的身份在没有用户知情的情况下,执行非授权的操作。了解CSRF攻击的机…...

如何从 Keras 中的深度学习目录加载大型数据集
一、说明 数据集读取,使用、在磁盘上存储和构建图像数据集有一些约定,以便在训练和评估深度学习模型时能够快速高效地加载。本文介绍Keras 深度学习库中的ImageDataGenerator类等工具自动加载训练、测试和验证数据集。 二、ImageDataGenerator加载数据集…...

【大数据】Flink 详解(八):SQL 篇 Ⅰ
《Flink 详解》系列(已完结),共包含以下 10 10 10 篇文章: 【大数据】Flink 详解(一):基础篇【大数据】Flink 详解(二):核心篇 Ⅰ【大数据】Flink 详解&…...

如何从命令行运行testng.xml?
目录 创建一个新的java项目并从命令行运行testng.xml 使用命令行运行XML文件 从命令行运行现有maven项目的XML文件 在这篇文章中,我们将使用命令行运行testng.xml。有多种场景需要使用命令行工具运行testng.xml。也许您已经创建了一个maven项目,现在想…...

MongoDB-数据库文档操作(2)
任务描述 文档数据在 MongoDB 中的查询和删除。 相关知识 本文将教你掌握: 查询文档命令;删除文档命令。 查询文档 我们先插入文档到集合 stu1 : document([{ name:张小华, sex:男, age:20, phone:12356986594, hobbies:[打篮球,踢足球…...
文件包含介绍
本地文件包含 常见的文件包含漏洞的形式为 <?php include("inc/" . $_GET[file]); ?> 考虑常用的几种包含方式为 同目录包含file.htaccess目录遍历?file…/…/…/…/…/…/…/…/…/var/lib/locate.db日志注入?file…/…/…/…/…/…/…/…/…/var/log/a…...

C语言——小细节和小知识9
一、大小端字节序 1、介绍 在计算机系统中,大小端(Endianness)是指多字节数据的存储和读取顺序。它是数据在内存中如何排列的问题,特别是与字节顺序相关。C语言中的数据存储大小端字节序指的是在内存中存储的多字节数据类型&…...
uni-app基础详解(组件、弹窗、数据缓存、页面跳转)
uni-app基础详解(组件、弹窗、数据缓存、页面跳转) uni-app组件scroll-viewswipertext 文本button 按钮input 输入框radio 单选checkbox 多选picker 选择器slider 滑块textarea 文本域 弹窗提示框 uni.showLoading提示弹窗 uni.showToast确定取消框 uni.…...

LabVIEW模拟荧光显微管滑动实验
LabVIEW模拟荧光显微管滑动实验 在现代生物医学研究中,对微观生物过程的精准模拟和观察至关重要。本案例展示了如何利用LabVIEW软件和专业硬件平台,创新地模拟荧光显微管在滑动实验中的动态行为,这一过程不仅提升了实验效率,还为…...
Springboot项目:解决@Async注解获取不到上下文信息问题
问题描述 springboot项目中,需要使用到异步调用某个方法,此时 第一个想到的就是 Async 注解,但是 发现 方法执行报错了,具体报错如下: java.lang.NullPointerExceptionat com.ruoyi.common.utils.ServletUtils.getRe…...

国内镜像:极速下载编译WebRTC源码(For Android/Linux/IOS)(二十四)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…...
ThinkPHP为什么用PHP+Swoole协程模式部署运行
看很多ThinkPHP框架的程序商城等系统,现在都用PHPSwoole协程来运行。在说Swoole前我们先了解下传统PHP模式。 PHP-FPM 的对象常驻内存问题 互联网发展早期,大部分项目的业务逻辑并没有那么复杂,技术生态相对比较简单,也没有 Com…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...