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…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...

HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...