当前位置: 首页 > 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…...

Linux系统安装Redis详细操作步骤(二进制发布包安装方式)

安装方式介绍 在Linux系统中&#xff0c;安装软件的方式主要有四种&#xff0c;这四种安装方式的特点如下&#xff1a; 安装方式特点二进制发布包安装软件已经针对具体平台编译打包发布&#xff0c;只要解压&#xff0c;修改配置即可rpm安装软件已经按照redhat的包管理规范进…...

Jenkins和Gitlab整合构建CI/CD流水线

配置环境 虚拟机建议4G起步 192.168.58.199 192.168.58.200 部署Jenkins 部署Jenkins参考这篇文章&#xff1a;Jenkins安装部署_connecting to pkg.jenkins.io (pkg.jenkins.io)|151.-CSDN博客 安装完毕之后根据下图操作 选择git&#xff0c;添加git仓库克隆url&#xff0c;选…...

14 C语言中的关键字

C语言中的关键字 在C语言中&#xff0c;关键字是一些预定义的单词&#xff0c;它们具有特殊的意义和用途。这些关键字不能用作标识符&#xff0c;比如变量名、函数名等&#xff0c;因为它们被保留用于特定的语言结构和操作。 关键字的分类 C语言的关键字可以分为几个主要类别…...

(11)(2.1.7) FETtec OneWire ESCs(一)

文章目录 前言 1 去哪里买 2 连接 3 组态 前言 &#xff01;Note 此功能在固件版本 4.1.1 及更高版本上可用。 OneWire 是 FETtec 的 ESC 双向通信协议(ESC bi-directional communication protocol)。 FETtec OneWire ESC 的遥测信息被发送回自动驾驶仪&#xff1a; 电…...

Python 异步编程:使用 `asyncio.to_thread` 和 `asyncio.Queue` 处理任务队列

Python 异步编程&#xff1a;使用 asyncio.to_thread 和 asyncio.Queue 处理任务队列 1. 什么是 asyncio.to_thread&#xff1f;2. 什么是 asyncio.Queue&#xff1f;3. 示例代码&#xff1a;使用 asyncio.to_thread 和 asyncio.Queue 处理任务队列示例代码代码解释运行结果 4.…...

【问题解决】Flink在linux上运行成功但是无法访问webUI界面

一&#xff0c;问题 在搭建Flink的时候&#xff0c;已经在linux服务器上运行了./start-cluster.sh&#xff0c; 而且日志显示已经成功了。 服务器上也没有开启防火墙 正常来说应该能通过ip:8081来访问(8081是Flink WebUI的默认端口)&#xff0c;但是访问的时候&#xff0c;显示…...

【问题解决】pnpm : 无法将“pnpm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。

今天配置完poetry环境变量之后pnpm不能用了 具体报错 pnpm : 无法将“pnpm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写&#xff0c;如果包括路径&#xff0c;请确保路径正确&#xff0c;然后再试一次。 所在位置 行:1 字符: 1pnpm run dev~~~~ Ca…...

微信网页授权回调地址放多个参数的方法

https://open.weixin.qq.com/connect/oauth2/authorize?appidAPPID&redirect_uriREDIRECT_URI&response_typecode&scopeSCOPE&stateSTATE#wechat_redirect 跳转后地址 redirect_uri/?codeCODE&stateSTATE。 redirect_uri如果不进行urlencode编码, 跳转后…...

相机工作距离计算

镜头 基础参数 焦距 ​ 例如&#xff0c;使用1英寸靶面(12.8mm x 9.6mm)的相机&#xff0c;工作距离WD是300mm&#xff0c;视野FOV的高度是120mm&#xff0c;那么光学放大倍率&#x1d6fd; 9.6&#x1d45a;&#x1d45a;/120&#x1d45a;&#x1d45a;0.08 &#xff0c;…...

Pandas模块之垂直或水平交错条形图

目录 df.plot() 函数Pandas模块之垂直条形图Pandas模块之水平交错条形图 df.plot() 函数 df.plot() 是 Pandas 中的一个函数&#xff0c;用于绘制数据框中的数据。它是基于 Matplotlib 库构建的&#xff0c;可以轻松地创建各种类型的图表&#xff0c;包括折线图、柱状图、散点…...

乌鲁木齐企业网站建设公司/中国国家人才培训网官网

写在前面mysql在开发过程中使用率比较高的数据库&#xff0c;linux下安装也挺简单&#xff0c;主要是一些配置容易忽略&#xff0c;文件权限比较复杂&#xff0c;下面例子使用超级用户(root)安装mysql5.6。默认mysql安装的权限是mysql用户组的mysql用户&#xff0c;不需要手动去…...

php可以做网站app吗/如何快速提升网站关键词排名

出现这种错误的原因就是&#xff1a;你入参的数值超过了数据库中定义的类型长度&#xff0c;这时候需要修改数据库中的类型了。...

顺的品牌网站建设/品牌营销推广方案怎么做

# 周围可能有东西能帮到你。 # 首先&#xff0c;移动到橱柜。 hero.moveUp() hero.moveRight(2) hero.moveDown(2) # 然后&#xff0c;使用while-true循环攻击"Cupboard"&#xff08;橱柜&#xff09;。 while True: hero.attack("Cupboard")...

海南网站建设哪里有/广点通和腾讯朋友圈广告区别

--loop循环用法 (输出1到10) declare v_num number(2) : 0; begin loopv_num : v_num 1;exit when v_num > 10;--上面退出循环也可以用下面3行/* if(v_num > 9) thenexit;end if;*/dbms_output.put_line(v_num); end loop; end;--while loop循环用法 (输出1到10) decl…...

模块网站建设/石家庄网站优化

上周终于买到Windows Phone 7真机&#xff0c;近期将注册App Hub测试曾经写过的WP7项目&#xff0c;希望不久以后能和大家一起分享Windows Phone 7开发经验。 本周Silverlight学习资源更新&#xff1a;Silverlight中使用MVVM&#xff08;5&#xff09;&#xff1a;Command IIRi…...

53套网站源码/网站设计的毕业论文

Python入门从哪开始&#xff0c;90%以上的书上都是这样讲的&#xff1a;先介绍 Python 的基本语法规则、list、dict、tuple 等数据结构&#xff0c;然后再介绍字符串处理和正则表达式&#xff0c;介绍文件等IO操作.... 就这样一点一点往下说。然而这种按部就班的学习方法&#…...