Linux套接字通信学习
Linux套接字通信
在网络通信的时候, 程序猿需要负责的应用层数据的处理(最上层),而底层的数据封装与解封装(如TCP/IP协议栈的功能)通常由操作系统、网络协议栈或相关网络库(如Socket库)实现。(程序员只需要调用对应的API接口)
什么是Socket编程?
Socket套接字目的是将TCP/IP协议相关软件移植到UNIX类系统中。设计者开发了一个接口,以便应用程序能简单地调用该接口通信,这个接口不断完善,最终形成了Socket套接字。
简单来说:套接字对应程序猿来说就是一套网络通信的接口,使用这套接口就可以完成网络通信。
一、字节序:大端与小端
小端:主机字节序
- 低位字节存储到内存的低位地址
- PC机的数据存储默认小端
大端:网络字节序
- 低位字节存储到内存的高位地址
- 套接字通信过程中操作的数据都是大端存储的,包括:接收/发送的数据、IP地址、端口
主机字节序与网络字节序的转换函数
#include <arpa/inet.h> // h: host, 主机字节序 // n: net, 网络字节序 // s:short(port) // l:long(IP)// 这套api主要用于 网络通信过程中 IP 和 端口 的 转换 // 将一个短整形从主机字节序 -> 网络字节序 uint16_t htons(uint16_t hostshort); serv_addr.sin_port = htons(SERV_PORT);//举例:将端口号主机字节序转成网络字节序// 将一个整形从主机字节序 -> 网络字节序 uint32_t htonl(uint32_t hostlong); // 将一个短整形从网络字节序 -> 主机字节序 uint16_t ntohs(uint16_t netshort) // 将一个整形从网络字节序 -> 主机字节序 uint32_t ntohl(uint32_t netlong);
二、IP地址转换
IP地址本质是一个整形数,但是在使用的过程中都是通过一个字符串来描述,下面的函数描述了如何将一个字符串类型的IP地址进行大小端转换:
//IP地址转换函数(点分十进制(字符串)→ 网络二进制)
int inet_pton(int af, const char *src, void *dst);
/*af:AF_INET、AF_INET6src:传入参数,IP地址(点分十进制)dst:传出参数,转换后的 网络字节序的 IP地址。 返回值:转换是否成功
*///网络字节序→String
const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);
/*af:AF_INET、AF_INET6src: 传入参数,网络字节序IP地址dst:传出参数,主机字节序(string IP)size: dst 的大小。返回值:指向dst的指针,含格式化后的字符串形式 IP 地址。
*/
//仅限处理IPv4
// 点分十进制IP -> 大端整形
in_addr_t inet_addr (const char *cp);
// 大端整形 -> 点分十进制IP
char* inet_ntoa(struct in_addr in);
三、sockaddr 数据结构
//sockaddr的地址结构 man手册:man 7 ip
struct sockaddr_in {sa_family_t sin_family; /* address family: AF_INET */in_port_t sin_port; /* port in network byte order */struct in_addr sin_addr; /* internet address */
};
四、套接字相关函数
socket函数:
创建套接字
#include <sys/socket.h>int socket(int domain, int type, int protocol);
/*
domain: 使用的地址族协议AF_INET、AF_INET6
type:SOCK_STREAM流式传输协议、SOCK_DGRAM报文传输协议
protocol: 一般写0即可, 使用默认的协议
返回值:新套接字所对应文件描述符
*/
bind函数:
给socket绑定地址结构
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
/*
sockfd: socket文件描述符,socket()的返回值
addr: 传入的地址结构(包括IP和端口号)(struct sockaddr *)&addr struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(8888);addr.sin_addr.s_addr = htonl(INADDR_ANY);
addrlen: sizeof(addr) 地址结构的大小。
*/
listen函数:
设置同时与服务器建立连接的上限数
int listen(int sockfd, int backlog);
/*
sockfd: socket文件描述符,socket()的返回值
backlog: 上限连接数,max = 128
*/
★accept函数:
阻塞等待客户端建立连接,返回一个与客户端成功连接的socket文件描述符(一个新的用于通信的文件描述符)
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
/*
sockfd: 监听的文件描述符,socket()的返回值
addr:传出参数, 存储了建立连接的客户端的地址信息
addrlen: 传入传出参数,存储addr指向的内存大小
返回值:返回能与客户端进行数据通信的 socket 对应的文件描述。
*/
accept
函数被调用时,它会阻塞程序的执行,直到有客户端连接请求到达。- 当有客户端连接请求到达时,
accept
函数会接受连接请求,并创建一个新的套接字用于与客户端通信。这个新的套接字是一个专门用于与该客户端进行通信的套接字,而原始的服务器套接字仍然保持在监听状态以接受其他连接请求。 - 如果提供了非空的
addr
参数,accept
函数将会填充客户端的地址信息,包括IP地址和端口号。 accept
函数返回新创建的套接字的文件描述符。通过该文件描述符,服务器可以与客户端进行通信,发送和接收数据。
connect函数:
客户端socket与服务器建立连接。成功连接服务器之后, 客户端会自动随机绑定一个端口
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*
sockfd: socket文件描述符,socket()函数返回值
addr:要连接的服务器的地址结构(客户端通常无法自己指定端口号,由操作系统动态分配) struct sockaddr_in srv_addr; // 服务器地址结构srv_addr.sin_family = AF_INET;srv_addr.sin_port = 9527 跟服务器bind时设定的 port 完全一致。inet_pton(AF_INET, "服务器的IP地址",&srv_adrr.sin_addr.s_addr);
addrlen:服务器的地址结构的大小
*/
write/send函数:
向已建立链接的Socket的写缓冲区中写入数据
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
ssize_t send(int fd, const void *buf, size_t len, int flags);
/*fd: 用于通信的文件描述符, accept() 函数的返回值buf: 存放要写入的数据的缓冲区首地址count: 想要写入的字节数len: 要发送的字符串的长度flags: 特殊的属性, 一般不使用, 指定为 0返回值:实际发送的字节数
*/
read/recv函数:
从一个已建立连接的 Socket 读缓冲区中读取数据
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
ssize_t recv(int fd, void *buf, size_t size, int flags);
/*fd: 用于通信的文件描述符,accept() 函数的返回值buf: 一个指向内存区域的指针,用于存储读取到的数据count: 指定最多读取的字节数,即缓冲区大小。size: 参数buf指向的内存的容量flags: 特殊的属性, 一般不使用, 指定为 0返回值:实际发送的字节数 = 0,代表连接断开;= -1 接收数据失败
*/
⭐五、TCP通信流程
TCP面向连接、安全、流式传输。传输层协议
- 面向连接:是一个双向连接,通过三次握手完成,断开连接需要通过四次挥手完成。
- 安全:tcp通信过程中,会对发送的每一数据包都会进行校验, 如果发现数据丢失, 会自动重传
- 流式传输:发送端和接收端处理数据的速度,数据的量都可以不一致
TCP通信流程图:
5.1 服务端文件描述符种类
在tcp的服务器端, 有两类文件描述符(客户端只有通信的文件描述符)
监听的文件描述符
lfd
- 只需要有一个
- 不负责和客户端通信, 负责检测客户端的连接请求, 检测到之后调用accept就可以建立新的连接
通信的文件描述符
cfd
- 负责和建立连接的客户端通信
- 如果有N个客户端和服务器建立了新的连接, 通信的文件描述符就有N个,每个客户端和服务器都对应一个通信的文件描述符
⭐⭐⭐5.2 文件描述符的内存结构
强烈建议结合视频观看
文件描述符对应的内存结构:
一个文件文件描述符对应两块内存, 一块内存是读缓冲区, 一块内存是写缓冲区
- 注意:read/wirte函数并不是将数据直接发送/读取到网络流中,而是通过两个缓冲区进行操作,然后再由操作系统的内核来将缓冲区的数据发送到网络流中。
读数据: 通过文件描述符将内存中的数据读出, 这块内存称之为读缓冲区
写数据: 通过文件描述符将数据写入到内存中, 这块内存称之为写缓冲区
监听的文件描述符:
- 客户端的连接请求会发送到服务器端监听的文件描述符的读缓冲区中
- 读缓冲区中有数据, 说明有新的客户端连接
- 调用accept()函数, 这个函数会检测监听文件描述符的读缓冲区
- 检测不到数据, 该函数阻塞
- 如果检测到数据, 解除阻塞, 新的连接建立
通信的文件描述符:
- 客户端和服务器端都有通信的文件描述符
- 发送数据:调用函数 write() / send(),数据进入到内核中
- 数据并没有被发送出去, 而是将数据写入到了通信的文件描述符对应的写缓冲区中
- 内核检测到通信的文件描述符写缓冲区中有数据, 内核会将数据发送到网络中
- 接收数据: 调用的函数 read() / recv(), 从内核读数据
- 数据如何进入到内核程序猿不需要处理, 数据进入到通信的文件描述符的读缓冲区中
- 数据进入到内核, 必须使用通信的文件描述符, 将数据从读缓冲区中读出即可
int main(int argc, char* argv[]) {struct sockaddr_in serv_addr, clit_addr;socklen_t clit_addr_len;
//初始化服务器IP地址和端口号serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(SERV_PORT);serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//socketlfd = socket(AF_INET, SOCK_STREAM, 0);
//bindbind(lfd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr));
//listenlisten(lfd, 128);clit_addr_len = sizeof(clit_addr);
//accept:阻塞等待连接,当连接成功时,客户端的地址结构会填入clit_addrcfd = accept(lfd, (struct sockaddr *)&clit_addr, &clit_addr_len);
//TCP通信已建立,处理逻辑省略close(lfd);close(cfd);
}
5.3 客户端通信流程
只有一个用于通信的套接字
cfd
int main(int argc, char *argv[])
{int cfd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in serv_addr;serv_addr.sin_port = htons(SERV_PORT);serv_addr.sin_family = AF_INET;inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr.s_addr);int ret = connect(cfd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr));
//通信已建立,自行处理数据逻辑close(cfd);return 0;
}
参考文献
爱编程的大丙:B站同名视频
相关文章:

Linux套接字通信学习
Linux套接字通信 在网络通信的时候, 程序猿需要负责的应用层数据的处理(最上层),而底层的数据封装与解封装(如TCP/IP协议栈的功能)通常由操作系统、网络协议栈或相关网络库(如Socket库)实现。(程序员只需要…...

mybatis-plus 用法总结
MyBatis-Plus(简称 MP)是 MyBatis 的增强工具,旨在简化开发者的 CRUD 操作。它在 MyBatis 的基础上提供了更多的功能和便利性,如代码生成器、分页插件、性能分析插件等,使开发者能够更高效地进行数据库操作。MyBatis-P…...

小程序配置文件 —— 14 全局配置 - tabbar配置
全局配置 - tabBar配置 tabBar 字段:定义小程序顶部、底部 tab 栏,用以实现页面之间的快速切换;可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面; 在上面图中,标注了一些 tabBar …...

Redis-十大数据类型
Reids数据类型指的是value的类型,key都是字符串 redis-server:启动redis服务 redis-cli:进入redis交互式终端 常用的key的操作 redis的命令和参数不区分大小写 ,key和value区分 1、查看当前库所有的key keys * 2、判断某个key是否存在 exists key 3、查…...
linux系统编程(七)管道和FIFO
1、管道 使用系统调用pipe可以创建一个新管道: #include <unistd.h> int pipe(int filedes[2]);成功的pipe调用会在数组filedes中返回两个打开的文件描述符,读取端为filedes[0],写入端为filedes[1]。我们可以使用read/write系统调用在…...

【vLLM大模型TPS测试三部曲】
安装 pip install vllm模型自行下载 例如: https://modelscope.cn/models/jackle/Qwen2.5-Coder-32B-GPTQ-Int4/ 部署测试 export VLLM_MODELQwen2.5-Coder-32B-GPTQ-Int4 # 启动 python3 -m vllm.entrypoints.openai.api_server --model $VLLM_MODEL --deviceauto --enf…...

Elasticsearch:使用 Ollama 和 Go 开发 RAG 应用程序
作者:来自 Elastic Gustavo Llermaly 使用 Ollama 通过 Go 创建 RAG 应用程序来利用本地模型。 关于各种开放模型,有很多话要说。其中一些被称为 Mixtral 系列,各种规模都有,而一种可能不太为人所知的是 openbiollm,这…...

Windows平台ROBOT安装
Windows环境下ROBOT的安装,按照下文进行部署ROBOT的前提是你的python已安装并且环境变量已设置好. 一、安装setuptools 1、下载后安装 https://pypi.python.org/pypi/setuptools/ 下载你需要的包 setuptools-75.6.0.tar.gz 解压下载的包在命令行中进入该包,敲击如下命令后…...

【动态规划篇】穿越算法迷雾:约瑟夫环问题的奇幻密码
欢迎拜访:羑悻的小杀马特.-CSDN博客 本篇主题:带你众人皆知的约瑟夫环问题 制作日期:2024.12.29 隶属专栏:C/C题海汇总 目录 引言: 一约瑟夫环问题介绍: 11问题介绍: 1.2起源与历史背景&…...

代码随想录算法训练营第51期第32天 | 理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯
理论基础 动态规划:dp,每一个状态都是由上个状态推导出来的,因为我是先写完三道题再看理论的,所以有点感概; 确定dp数组(dp table)以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举…...

爱思唯尔word模板
爱思唯尔word模板 有时候并不一定非得latex https://download.csdn.net/download/qq_38998213/90199214 参考文献书签链接...
每日一题 354. 俄罗斯套娃信封问题
354. 俄罗斯套娃信封问题 需要对信封排序 ,重点是再宽度相同时,逐步减少其高度 class Solution { public:int maxEnvelopes(vector<vector<int>>& envelopes) {sort(envelopes.begin(),envelopes.end(),[](const vector<int>&a,const v…...

ASP.net网站的注册、登录和密码修改的操作详解
一、进入注册、登录和密码修改操作详解 ASP.net网站为用户提供不同权限状态下的操作界面。根据用户登录状态,页面会显示不同的选项。 已登录用户的操作 图1 登录后操作界面 当用户已登录系统时,会显示以下内容和功能: 1. 欢迎信息 页面顶部…...

2024.12.29(进程线程实现并发服务器)
作业 多进程多线程并发服务器实现一遍提交。 服务器 #include <myhead.h> #define PORT 12345 #define IP "192.168.124.123"void *fun(void *fd) {int newfd *(int *)fd;char buff[1024];while(1){int res recv(newfd,buff,sizeof(buff),0);if(res 0){p…...

如何在 Ubuntu 上安装 PyTorch
简介 PyTorch 因其易用性、动态计算图和高效性而日益流行,成为实现深度学习模型的首选。如果你想探索这个工具并学习如何在 Ubuntu 上安装 PyTorch,本指南将对你有所帮助! 在本教程中,我们将引导你完成在 Ubuntu 系统上使用 Pip…...

8-Gin 中间件 --[Gin 框架入门精讲与实战案例] 【文末有测试代码】
路由中间件 Gin 是一个用 Go (Golang) 编写的 HTTP web 框架。它以性能好、中间件支持灵活著称,非常适合用来构建微服务或 RESTful API 服务。下面我将提供三个使用 Gin 的路由中间件的完整示例。 示例 1: 简单的日志记录中间件 这个中间件会在每个请求处理前后打…...

【潜意识Java】深入详细理解分析Java中的toString()方法重写完整笔记总结,超级详细。
目录 一、toString() 方法是啥? (一)默认的 toString() 方法 (二)toString() 方法的作用 二、为啥要重写 toString() 方法? (一)提高代码的可读性 (二)…...

【论文笔记】Contrastive Learning for Sign Language Recognition and Translation
🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: Contrastive Learning for…...

Gitlab17.7+Jenkins2.4.91实现Fastapi/Django项目持续发布版本详细操作(亲测可用)
一、gitlab设置: 1、进入gitlab选择主页在左侧菜单的下面点击管理员按钮。 2、选择左侧菜单的设置,选择网络,在右侧选择出站请求后选择允许来自webhooks和集成对本地网络的请求 3、webhook设置 进入你自己的项目选择左侧菜单的设置ÿ…...
一起来看--红黑树
【欢迎关注编码小哥,学习更多实用的编程方法和技巧】 红黑树是一种自平衡的二叉搜索树,广泛应用于计算机科学中,尤其是在实现关联数组和集合时。它的设计旨在确保在最坏情况下,基本动态集合操作(如插入、删除和查找&am…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...

【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...