当前位置: 首页 > news >正文

linux网络编程5——Posix API和网络协议栈,使用TCP实现P2P通信

文章目录

  • Posix API和网络协议栈,使用TCP实现P2P通信
    • 1. socket()
    • 2. bind()
    • 3. listen()
    • 4. connect()
    • 5. accept()
    • 6. read()/write(), recv()/send()
    • 7. 内核tcp数据传输
      • 7.1 TCP流量控制
      • 7.2 TCP拥塞控制——慢启动/拥塞避免/快速恢复/快速重传
    • 8. shutdown()
    • 9. close()
      • 9.1 正常情况
      • 9.2 主动关闭方在fin_wait_1状态下先收到FIN
      • 9.3 双方同时收到FIN报文
    • 10. 使用TCP协议实现点对点通信
    • 学习参考

Posix API和网络协议栈,使用TCP实现P2P通信

本文介绍了linux Posix API涉及网络编程的常用函数,并解释其原理和涉及的网络协议栈。最后,利用TCP三次握手中同时打开建立连接的情况实现了P2P通信。

TCP状态转换图

1. socket()

socke()的主要作用是分配fd和建立tcb(tcp control block)

  • 分配fd,内部通过一个bitmap标记一个fd是否已被使用。
  • 建立tcb,alloc(),此时还没有分配接受缓冲区和发送缓冲区。

TCB 是操作系统内核中用于跟踪每个 TCP 连接的核心数据结构,包含了与连接相关的状态信息,比如源地址、目标地址、端口号、窗口大小、序列号等。

2. bind()

将本地ip和和端口绑定到fd对应的tcb中。客户端fd如果bind了的话,则本地端口就会固定。

3. listen()

  1. 将监听套接字tcb中的status设置为TCP_STATUS_LISTEN。
  2. 为监听套接字tcb分配两个队列:半连接队列syn_queue和全连接队列accept_queue
    • syn_queue,存储还未完成三次握手的请求。Linux 中的 tcp_max_syn_backlog决定了 syn_queue 的最大容量。
    • accpet_quque,存储已经完成三次握手,等待应用层调用accpet()的请求。如 Linux 中的 somaxconn决定了其容量。
int listen(int sockfd, int backlog);

其中backlog最早70年代指的是syn_queue队列的长度,也就是收到SYN但是还没有完成三次握手的请求的队列长度。中间指的是两个队列的长度之和的最大值。现在指的是accpet队列最大长度。这样应用程序可以主要关注待处理连接请求的数量。

tcp连接的生命周期,从什么时候开始?

从收到第一个SYN报文的时候开始,开始创建tcb,连接开始建立。

第三次握手的数据包,如何从半连接队列查找匹配的节点?

每一个TCP报文段中都包含源ip、目的ip、源端口等五元组信息,据此可以查找匹配。

如何解决SYN泛洪/DDOS攻击?

限制半连接队列的最大长度。

4. connect()

connect()用于客户端主动建立与对端的连接,可能有两种情况。

三次握手主要是为了通信的同步,交换序号信息,保证之后的通信不丢失、不乱序。

  1. 正常主动打开
image-20241025125049588
  1. 同时打开

适用于P2P通信,需要双方同时调用connect()。

image-20241025130536095

5. accept()

用于从全连接队列中取出一个连接,并分配fd。

水平触发

每次只接受一个连接,效率较低。

边缘触发 + 非阻塞IO

使用一个循环,如果accept返回-1并且errno为EAGAIN或者EWOULDBLOCK,则退出循环。

while (1)
{fd = accept(listen_fd, &clnt_addr, &clnt_addr_len);if (fd == -1){if (errno == EAGAIN || errno == EWOULDBLOCK)break;}// 处理新连接
}

6. read()/write(), recv()/send()

这些IO函数都是与系统内的接收缓冲区和发送缓冲区之间传输数据,而非直接与网卡。tcp报文段的接受与发送和这些IO函数没有一对一的关系。

7. 内核tcp数据传输

TCP协议头

在这里插入图片描述

7.1 TCP流量控制

滑动窗口

TCP使用了滑动窗口中的回退n自动重复请求机制。原理是当某个数据段未被正确接收,则接收方不会确认其后续的数据段;当发送方发现超时或者收到重复的ACK时,会回退到未被确认的第一个数据段继续发送。

延迟确认

如果数据乱序到达,可以等待一段时间,在进行确认。

超时重传

7.2 TCP拥塞控制——慢启动/拥塞避免/快速恢复/快速重传

慢启动是 TCP 在建立连接或从网络拥塞中恢复时使用的拥塞控制算法,旨在探测网络的可用带宽,并逐步增加发送速率,避免在一开始就超载网络。

发送端在收到一个ACK之前,发送窗口的大小是由接收端接收窗口大小和本端拥塞窗口的大小决定的。

慢启动算法是指发送端拥塞窗口在到达慢启动阈值之前(称之为慢启动姐阶段)进行指数级增长。到达ssthresh(slow start threshhold)后进入拥塞避免阶段,拥塞窗口进行线性增长。当超时重传时,ssthresh变为当前拥塞窗口的一半,并重新开始慢启动阶段。

快速恢复用于在丢包被检测到(连续收到三个重复ACK)后,不必将拥塞窗口完全重置为 1 MSS,而是通过调整 cwndssthresh,更快地恢复到稳定传输的状态。

连续收到三个重复ACK,说明这与超时不同,表明网络可能并未完全拥塞,仍然存在一定的可用带宽。

具体来说,当检测到丢包时,发送方将 慢启动阈值 (ssthresh) 设置为当前 cwnd 的一半,然后发送方将 cwnd 减小到 ssthresh 的大小,同时跳过慢启动阶段,直接进入拥塞避免阶段。收到连续三个重复ACK时,也会对数据进行快速重传,而非等到超时。

8. shutdown()

进行半关闭,关闭写端。不推荐使用,因为它会使代码逻辑变复杂。

9. close()

当通信两端有调用close()来关闭tcp连接时,可能会发生以下三种交互情况。

9.1 正常情况

image-20241023201936418

9.2 主动关闭方在fin_wait_1状态下先收到FIN

image-20241023202659220

9.3 双方同时收到FIN报文

image-20241023202946556

10. 使用TCP协议实现点对点通信

参考4. connect()中的同时打开模型。让双方同时(在超时周期之内)调用connect即可。演示代码如下:

client1.c

#include <stdio.h>
#include <string.h>#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>int main(int argc, char const *argv[])
{struct sockaddr_in local_addr = {0}, peer_addr = {0};int sock_fd = socket(PF_INET, SOCK_STREAM, 0);local_addr.sin_family = AF_INET;local_addr.sin_addr.s_addr = htonl(INADDR_ANY);local_addr.sin_port = htons(2000);peer_addr.sin_family = AF_INET;peer_addr.sin_addr.s_addr = inet_addr("127.0.0.1");peer_addr.sin_port = htons(2001);if (bind(sock_fd, (struct sockaddr *)&local_addr, sizeof local_addr) == -1){perror("bind()");close(sock_fd);return 1;}char message[100] = "hello I am KAKA";while (1){if (connect(sock_fd, (struct sockaddr *)&peer_addr, sizeof peer_addr) == -1){usleep(50);continue;}write(sock_fd, message, strlen(message));close(sock_fd);break;}return 0;
}

client2.c

#include <stdio.h>
#include <string.h>#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>int main(int argc, char const *argv[])
{struct sockaddr_in local_addr = {0}, peer_addr = {0};int sock_fd = socket(PF_INET, SOCK_STREAM, 0);local_addr.sin_family = AF_INET;local_addr.sin_addr.s_addr = htonl(INADDR_ANY);local_addr.sin_port = htons(2001);if (bind(sock_fd, (struct sockaddr *)&local_addr, sizeof local_addr) == -1){perror("bind()");close(sock_fd);return 1;}peer_addr.sin_family = AF_INET;peer_addr.sin_addr.s_addr = inet_addr("127.0.0.1");peer_addr.sin_port = htons(2000);char buf[100];int received;while (1){if (connect(sock_fd, (struct sockaddr *)&peer_addr, sizeof peer_addr) == -1){usleep(50);continue;}if ((received = read(sock_fd, buf, sizeof buf - 1)) != 0){if (received == -1){perror("read()");close(sock_fd);return 1;}buf[received] = 0;printf("from peer:\n%s\n", buf);}close(sock_fd);break;}return 0;
}

学习参考

学习更多相关知识请参考零声 github。

相关文章:

linux网络编程5——Posix API和网络协议栈,使用TCP实现P2P通信

文章目录 Posix API和网络协议栈&#xff0c;使用TCP实现P2P通信1. socket()2. bind()3. listen()4. connect()5. accept()6. read()/write(), recv()/send()7. 内核tcp数据传输7.1 TCP流量控制7.2 TCP拥塞控制——慢启动/拥塞避免/快速恢复/快速重传 8. shutdown()9. close()9…...

低代码平台中的功能驱动开发:模块化与领域设计

在现代软件开发中&#xff0c;尤其是在低代码平台的背景下&#xff0c;清晰地定义功能和模块是成功的关键。功能驱动开发强调功能的优先性&#xff0c;模块化设计则确保系统的可维护性和可扩展性。本文将探讨如何在低代码平台中有效地将功能与模块结合起来&#xff0c;形成一个…...

HTTP和HTTPS基本概念,主要区别,应用场景

HTTP和 HTTPS是用于在网络中传输数据的协议&#xff0c;虽然它们的功能类似&#xff0c;但在安全性上存在显著差异。 1. HTTP 的基本概念 定义&#xff1a;HTTP 是一种无状态的、面向请求-响应的协议&#xff0c;用于客户端&#xff08;如浏览器&#xff09;和服务器之间传输…...

node.js使用Sequelize ORM操作数据库

一、什么是ORM ORM是在数据库和编程语言之间建立一种映射关系&#xff0c;这样可以让我们有非常简单的代码&#xff0c;来实现各种数据库的操作。 例如&#xff1a;使用mysql去查找表&#xff08;表名称为Articles&#xff09; SELECT * FROM Articles;但是我们使用ORM的话&…...

STM32-Modbus协议(一文通)

Modbus协议原理 RT-Thread官网开源modbus RT-Thread官方提供 FreeModbus开源。 野火有移植的例程。 QT经常用 libModbus库。 Modbus是什么&#xff1f; Modbus协议&#xff0c;从字面理解它包括Mod和Bus两部分&#xff0c;首先它是一种bus&#xff0c;即总线协议&#xff0c;和…...

100. 不同方向的投影视图

本节课给大家讲解&#xff0c;通过UI按钮界面交互改变threejs相机的观察视角。 x轴方向观察 // 通过UI按钮改变相机观察角度 document.getElementById(x).addEventListener(click, function () {camera.position.set(500, 0, 0); //x轴方向观察camera.lookAt(0, 0, 0); //重新…...

Appium中的api(三)

目录 Appium中的api(三) 1.输入和清空内容 1--输入内容 2--清空内容 2.获取文本内容 3.获取文本位置 4.获取文本的大小&#xff08;即获取控件的宽和高&#xff09; 5.滑动api 6.拖拽api 7.如何获取手机分辨率 8.如何截图 9.模拟按键事件api 10.操作通知栏 案例:App自动化模拟 …...

踩坑:关于使用ceph pg repair引发的业务阻塞

概述 在某次故障回溯中&#xff0c;发现引发集群故障&#xff0c;slow io&#xff0c;pg stuck的罪魁祸首竟是做了一次ceph pg repair $pgid。然而ceph pg repair作为使用频率极高的&#xff0c;用来修复pg不一致的常用手段&#xff0c;平时可能很少注意其使用规范和可能带来的…...

瞬间升级!电子文档华丽变身在线题库,效率翻倍✨

&#x1f44b;嘿小伙伴们&#xff0c;有个超赞的秘籍要告诉你们——土著刷题能将你的电子文档一键变身在线题库&#xff01;&#x1f609; 你还没发现这个宝藏功能吗&#xff1f;快来瞧瞧&#xff01; &#x1f31f;是不是常被一堆电子版的学习资料搞得头昏脑涨&#xff0c;学习…...

如何动态改变本地的ip

在当今数字化时代&#xff0c;网络连接已成为我们日常生活和工作中不可或缺的一部分。无论是出于隐私保护、突破地域限制&#xff0c;还是为了测试和优化网络应用&#xff0c;动态改变本地IP地址的需求日益增多。本文将详细介绍如何安全、有效地实现这一目标&#xff0c;旨在帮…...

Spring Boot框架在中小企业设备管理中的创新应用

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…...

Ceph入门到精通-Osd db扩容

ceph-bluestore-tool 是一个在 BlueStore 实例上执行低级管理操作的实用程序。 以下命令可用于 ceph-bluestore-tool 语法 ceph-bluestore-tool COMMAND [ --dev DEVICE … ] [ -i OSD_ID ] [ --path OSD_PATH ] [ --out-dir DIR ] [ --log-file | -l filename ] [ --deep ]c…...

windows msvc2017 x64编译AWS SDK CPP库

在本文中&#xff0c;我们将介绍如何编译AWS SDK C库&#xff0c;以便在您的项目中使用。AWS SDK C库提供了与Amazon Web Services交互的接口&#xff0c;允许您在C应用程序中使用AWS服务。 一、准备工作 在开始编译AWS SDK C库之前&#xff0c;请确保您的系统已经安装了以下…...

铜业机器人剥片 - SNK施努卡

SNK施努卡有色行业电解车间铜业机器人剥片 铜业机器人剥片技术是针对传统人工剥片效率低下、工作环境恶劣及生产质量不稳定的痛点而发展起来的自动化解决方案。 面临人工剥片的诸多挑战&#xff0c;包括低效率、工作环境差、人员流动大以及产品质量控制不精确等问题。 人工剥片…...

非接触式竖向位移、水平位移视频实时在线监测的设备分类及选型

前言 视觉是人工智能正在快速发展的一个分支&#xff0c;简单说来&#xff0c;机器视觉就是用机器代替人眼来做测量和判断。在结构健康自动化监测方面&#xff0c;机器视觉采用光学图像结合智能算法和物联网技术&#xff0c;利用先进的智能靶标识别及亚像素处理等技术&#xff…...

Svelte 5 正式发布:新一代前端框架!

10 月 22 日&#xff0c;Svelte 5 正式发布&#xff01;该版本带来的更新主要包括&#xff1a; 重写框架&#xff1a;Svelte 5 是从头开始重写的&#xff0c;使得应用更快、更小、更可靠&#xff0c;并且代码更一致和符合习惯。 向后兼容&#xff1a;Svelte 5 几乎完全向后兼容…...

85.【C语言】数据结构之顺序表的中间插入和删除及遍历查找

目录 3.操作顺序表 1.分析中间插入函数 函数的参数 代码示例 图片分析 main.c部分改为 在SeqList.h添加SLInsert函数的声明 运行结果 2.分析中间删除函数 函数的参数 代码示例 图片分析 main.c部分改为 在SeqList.h添加SLErase函数的声明 运行结果 承接84.【C语…...

触觉智能Purple Pi OH鸿蒙开发板成功适配OpenHarmony5.0 Release,开启新征程!

10月22日&#xff0c;触觉智能Purple Pi OH鸿蒙开发板迎来了重大系统版本升级&#xff0c;成功适配OpenHarmony5.0 Release&#xff0c;为嵌入式开发者和科技爱好者们带来了全新的机遇与挑战&#xff01; 触觉智能 Purple Pi OH 开发板一直以来都以其高品质和超高性价比而著称。…...

分布式解决方案---分布式ID

目录 是什么 特点 全局唯一 高并发 高可用 怎么做 实现方案 是什么 分布式ID是指在分布式系统中生成的唯一标识符。由于分布式系统的特点&#xff0c;多个节点可能会同时生成ID&#xff0c;因此需要确保每个ID在整个系统中是唯一的。 重点就是唯一性&#xff01;&#x…...

httpd服务

文章目录 1、搭建一个网络yum源2、基于域名访问的虚拟主机3、基于端口来访问域名4、搭建个人网站5、加密访问显示自定义网页内容 1、搭建一个网络yum源 [roottest01 conf.d]# cat repo.conf <virtualhost *:80>documentroot /var/www/html/ServerName 10.104.43.154ali…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...