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…...

SpringBoot整合篇 05、Springboot整合Redission
文章目录 前言Redission详细配置步骤pom依赖application.yaml配置类CacheConfigEnvironmentContext RedissionController单测 前言 本篇博客是SpringBoot整合Redission,若文章中出现相关问题,请指出! 所有博客文件目录索引:博客…...

供应链系统设计-供应链中台系统设计(六)- 商品中心概念篇
概述 我们在供应链系统设计-中台系统设计系列(五)- 供应链中台实践概述 中描述了什么是供应链中台,供应链中台主要包含了那些组成部门。包括业务中台、通用中台等概念。为了后续方便大家对于中台有更深入的理解,我会逐一针对中台…...

胡闹厨房练习(三)
ScriptableObject 一、初步了解 1、实质:是一种特殊类型的Unity对象, 2、作用:用于存储大量数据,而不必依附于游戏场景中的某个GameObject。 3、特点: 可以在不增加场景中对象数量的情况下,管理和存储复杂的数据结构、配置信息、游戏状态等。 4、适用:非常适合用来…...
关于ESD(静电放电)等级的划分
关于ESD(静电放电)等级的划分,主要依据不同的测试模型和测试标准。以下是对HBM(人体模型)和CDM(充电器件模型)两种测试模型下ESD等级划分的详细解释: HBM ESD等级划分 HBM ESD等级…...

探究步进电机与输入脉冲的关系
深入了解步进电机 前言一、 步进电机原理二、 细分三、脉冲数总结 前言 主要是探究以下内容: 1、步进电机的步进角。 2、什么是细分。 3、脉冲的计算。 最后再扩展以下STM32定时器的计算方法。 一、 步进电机原理 其实语言描述怎么样都不直观,我更建议…...

基于YOLOV5+Flask安全帽RTSP视频流实时目标检测
1、背景 在现代工业和建筑行业中,安全始终是首要考虑的因素之一。特别是在施工现场,工人佩戴安全帽是确保人身安全的基本要求。然而,人工监督难免会有疏漏,尤其是在大型工地或复杂环境中,确保每个人都佩戴安全帽变得非…...

Windows内置的服务器IIS(Internet Information Services)托管网站
一. 安装IIS 打开控制面板:在开始菜单搜索“控制面板”并打开它。程序和功能:点击“程序”然后选择“程序和功能”。启用或关闭Windows功能:在左侧菜单中选择“启用或关闭Windows功能”。查找并勾选IIS:在弹出的窗口中,…...
虚幻引擎结构之UObject
一. UObject 的介绍 UObject 是虚幻引擎中的核心基础类,所有其他游戏对象和资源类都直接或间接地继承自它。作为虚幻引擎的基石,UObject 提供了多项关键功能,包括内存管理、序列化、反射(introspection)、垃圾回收以及元数据支持。在虚幻引擎中,UObject 类的实例通常被称…...
js的Reflect对象
Reflect 对象是 JavaScript ES6 中引入的一个内建对象,它提供了一系列与对象操作相关的方法。这些方法与 Object 对象上的方法类似,但在行为上有一些差异,并且更加规范和统一。Reflect 对象并不是一个构造函数,不能被 new 操作符调…...
this指向了谁?
看函数在执行的时候是如何调用的, 1 如果这个函数是用普通函数调用模式来进行调用,它内部的this指向了window; 2 如果一个函数在调用的时候是通过对象方法模式来进行调用,则它内部的this就是我们的对象; 3 如果一个函数在调用的时候通过构…...