文章目录

  • 91. TCP断开连接的时候为什么必须4次而不是3次?
  • 92. 为什么要区分用户态和内核态?
  • 93. 说说编写socket套接字的步骤
    • 1. 服务器端编写步骤
      • 1.1 创建套接字
      • 1.2 绑定套接字
      • 1.3 监听连接
      • 1.4 接受连接
      • 1.5 数据传输
      • 1.6 关闭套接字
    • 2. 客户端编写步骤
      • 2.1 创建套接字
      • 2.2 连接服务器
      • 2.3 数据传输
      • 2.4 关闭套接字
  • 94. 什么是大小端模式,编写代码区分大小端
    • 如何检查自己的电脑 是大端还是小端?
      • 第一种方法:
      • 第二种方法:
  • 95. 代码实现:实现简单的智能指针

91. TCP断开连接的时候为什么必须4次而不是3次?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

92. 为什么要区分用户态和内核态?

在这里插入图片描述
在这里插入图片描述

93. 说说编写socket套接字的步骤

在这里插入图片描述
编写一个基于套接字(socket)的网络程序通常包括以下步骤,无论是客户端还是服务器都需要遵循这些步骤。下面分别说明服务器和客户端编写的步骤,这些是简单的代码示例,仅仅帮助大家去理解这个过程。

1. 服务器端编写步骤

1.1 创建套接字

使用 socket() 函数创建一个套接字。这个函数返回一个套接字描述符,用于后续的操作。

int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {perror("socket failed");exit(EXIT_FAILURE);
}

1.2 绑定套接字

将创建的套接字绑定到指定的 IP 地址和端口号上,使用 bind() 函数。

struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");close(server_fd);exit(EXIT_FAILURE);
}

网络字节序是大端模式
在这里插入图片描述
address.sin_addr.s_addr = INADDR_ANY;指绑定端口到本地所有网络接口
在这里插入图片描述

1.3 监听连接

使用 listen() 函数使套接字进入监听状态,等待客户端连接请求。

if (listen(server_fd, 3) < 0) {perror("listen");close(server_fd);exit(EXIT_FAILURE);
}

1.4 接受连接

使用 accept() 函数接受客户端的连接请求,返回一个新的套接字描述符,用于与客户端通信。

int new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
if (new_socket < 0) {perror("accept");close(server_fd);exit(EXIT_FAILURE);
}

1.5 数据传输

使用 read() 和 write() 函数(或 recv() 和 send() 函数)进行数据的接收和发送。

char buffer[1024] = {0};
read(new_socket, buffer, 1024);
printf("Message from client: %s\n", buffer);
send(new_socket, "Hello from server", strlen("Hello from server"), 0);

1.6 关闭套接字

完成通信后,使用 close() 函数关闭套接字。

close(new_socket);
close(server_fd);

2. 客户端编写步骤

2.1 创建套接字

与服务器端类似,使用 socket() 函数创建一个套接字。

int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {perror("socket failed");exit(EXIT_FAILURE);
}

2.2 连接服务器

使用 connect() 函数将套接字连接到服务器端的指定 IP 地址和端口号。

struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {perror("Invalid address/ Address not supported");close(sock);exit(EXIT_FAILURE);
}if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("Connection Failed");close(sock);exit(EXIT_FAILURE);
}

2.3 数据传输

同样使用 read() 和 write() 或 recv() 和 send() 进行数据的发送和接收。

send(sock, "Hello from client", strlen("Hello from client"), 0);
char buffer[1024] = {0};
read(sock, buffer, 1024);
printf("Message from server: %s\n", buffer);

2.4 关闭套接字

完成通信后,使用 close() 函数关闭套接字。

close(sock);

94. 什么是大小端模式,编写代码区分大小端

在这里插入图片描述
在这里插入图片描述

如何检查自己的电脑 是大端还是小端?

第一种方法:

#include <iostream>  bool isLittleEndian() {  int num = 1;  // 数值 1 的 32 位表示是:0x00 00 00 01(从高到低 4 个字节)。// 大端(big-endian)把最高有效字节放在最低地址,所以内存从低地址到高地址是:// 00 00 00 01// 于是 reinterpret_cast<char*>(&num) 指向的第一个字节就是 0x00// 小端(little-endian)相反,把最低有效字节放在最低地址,所以是:// 01 00 00 00// 这时第一个字节是 0x01// 换个更形象的例子:如果 num = 0x12 34 56 78,// 大端内存排布(低→高地址):12 34 56 78// 小端内存排布(低→高地址):78 56 34 12char *c = reinterpret_cast<char*>(&num);  return *c == 1; // 如果最低有效字节在最低地址处,则为小端字节序  
}  int main() {  if (isLittleEndian()) {  std::cout << "This is a little-endian system." << std::endl;  } else {  std::cout << "This is a big-endian system." << std::endl;  }  return 0;  
}

在这里插入图片描述

第二种方法:

利用数据类型的存储方式来判断当前系统的字节序。常见的实现方法是使用 union 联合体来共享内存,并通过访问不同的成员来检查数据的存储顺序。

#include <iostream>
#include <cstdint>// 定义一个联合体,包含一个整数和一个字符数组
// 联合体(union)的所有成员共享同一段内存;写一个成员,换个成员读,能看到相同内存里的原始字节
union {// uint8_t:精确 8 位 无符号整数,范围 0 ~ 255。// uint32_t:精确 32 位 无符号整数,范围 0 ~ 4,294,967,295。uint32_t i;      // 32 位整数uint8_t c[4];    // 4 字节字符数组
} test;int main() {test.i = 0x12345678;  // 将一个已知的 32 位整数存入联合体中// 根据第一个字节的值判断大小端if (test.c[0] == 0x78) {std::cout << "小端模式 (Little-endian)" << std::endl;} else if (test.c[0] == 0x12) {std::cout << "大端模式 (Big-endian)" << std::endl;} else {std::cout << "无法确定字节序" << std::endl;}return 0;
}

在这里插入图片描述

在这里插入图片描述

95. 代码实现:实现简单的智能指针

下面是一个简单的智能指针实现的例子,用于管理动态分配的内存,避免内存泄漏。这个示例实现了一个类似于 std::shared_ptr 的简单智能指针,叫做 SimpleSmartPointer,它使用引用计数来管理对象的生命周期。

是在定义一个新对象 sp2,带着一个“初始值”sp1。
在 C++ 里,带初始值的定义叫“拷贝初始化(copy-initialization)”,它会调用拷贝构造函数(或能匹配的移动构造),不会调用赋值运算符。赋值运算符只在对象已经存在之后再用 = 给它“换内容”时才会被调用。SimpleSmartPointer<int> a(new int(10));// 1) 拷贝初始化:调用拷贝构造函数
SimpleSmartPointer<int> b = a;     // == SimpleSmartPointer<int> b(a);// 2) 直接初始化:也调用拷贝构造函数
SimpleSmartPointer<int> c(a);// 3) 先默认构造一个对象,再赋值:调用赋值运算符 operator=
SimpleSmartPointer<int> d;         // 等价于 SimpleSmartPointer<int> d(nullptr);
d = a;                             // 这里才会走你的 operator=
#include <iostream>// 简单智能指针类
template<typename T>
class SimpleSmartPointer {
private:T* ptr;          // 原生指针unsigned* count; // 引用计数public:// 构造函数,接受一个原生指针//这个explicit 主要目的是防止隐式类型转换。提高代码可读性和安全性explicit SimpleSmartPointer(T* p = nullptr) : ptr(p) {if (p) {count = new unsigned(1); // 初始化引用计数为1} else {count = nullptr;}}// 拷贝构造函数SimpleSmartPointer(const SimpleSmartPointer<T>& sp) : ptr(sp.ptr), count(sp.count) {if (count) {(*count)++; // 增加引用计数}}// 赋值运算符重载SimpleSmartPointer<T>& operator=(const SimpleSmartPointer<T>& sp) {if (this == &sp) {return *this; // 防止自我赋值}// 释放当前资源//--(*count):对 *count(引用计数值)进行自减操作,表示当前对象不再使用该资源//如果 *count 为 0,说明已经没有其他智能指针对象在使用这个资源了,此时需要释放资源if (count && --(*count) == 0) {delete ptr;delete count;}// delete ptr; 释放的是 ptr 指向的那块堆内存(并调用析构),并不会“删掉变量 ptr 本身”// 赋值新资源ptr = sp.ptr;count = sp.count;if (count) {(*count)++;}return *this;}// 解引用运算符重载// 返回类型:对 T 的引用。有了引用返回,*sp 就是一个可当左值用的对象(能读也能改)。// 函数名是个特殊运算符函数:重载“一元解引用运算符 *”。// 调用方式:*sp 等价于 sp.operator*()// operator* 是运算符重载函数,重载的是“一元解引用运算符 *”(注意不是乘法;乘法是二元 *)。// 这是一个成员函数,当你写 *sp 时,编译器会把它当作:// sp.operator*()   // 调用你这个函数// ptr 是你类里存的裸指针(T*)。// *ptr 是对这个裸指针的解引用,得到“那个 T 对象本身”。结合返回类型 T&,就把“托管对象”的引用交给了调用者。T& operator*() const {return *ptr;}// 指针访问运算符重载// T* operator->() const { return ptr; }// 把内部的裸指针 ptr(类型 Point*)拿出来,然后再用普通指针的 -> 去调用 print() / move() / 访问 x、y。所以 p->成员 就能像真指针那样用起来了// 前提是裸指针对应的数据结构里面有定义成员变量或者成员函数// operator->() 只有在 T 有成员时才有用;你现在用的是 SimpleSmartPointer<int>,int 没成员,所以用不上。给它换个有成员的类型,比如 Point,就能直接写 sp->成员/方法 了。T* operator->() const {return ptr;}// 返回当前共享计数;空指针时按惯例返回 0unsigned use_count() const {return count ? *count : 0;}// 获取原生指针T* get() const {return ptr;}// 析构函数 RAII~SimpleSmartPointer() {if (count && --(*count) == 0) {delete ptr;delete count;}}
};// 测试函数
void testSimpleSmartPointer() {// sp1.ptr 指向“int(10)”;// sp1.count 指向一块 unsigned,其值 *count == 1SimpleSmartPointer<int> sp1(new int(10));  // 创建一个智能指针,管理整数10std::cout << "sp1: " << *sp1 << std::endl; // 输出sp1所指向的值std::cout << "sp1.use_count() = " << sp1.use_count() << "\n";{// 拷贝构造函数  ← 就是被 “SimpleSmartPointer<int> sp2 = sp1;” 调用的这个SimpleSmartPointer<int> sp2 = sp1;    // sp2与sp1共享同一块内存*sp2 = 33;std::cout << "sp2: " << *sp2 << std::endl; // 输出sp2所指向的值std::cout << "sp2.use_count() = " << sp2.use_count() << "\n";std::cout << "sp1.use_count() = " << sp1.use_count() << "\n";} // sp2超出作用域,引用计数减1// 再次输出sp1所指向的值std::cout << "sp1: " << *sp1 << std::endl;std::cout << "sp1.use_count() = " << sp1.use_count() << "\n";
}int main() {testSimpleSmartPointer();return 0;
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

之后我会持续更新,如果喜欢我的文章,请记得一键三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路上的无限动力 !!!↖(▔▽▔)↗感谢支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/918343.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/918343.shtml
英文地址,请注明出处:http://en.pswp.cn/news/918343.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一个基于 epoll 实现的多路复用 TCP 服务器程序,相比 select 和 poll 具有更高的效率

/*5 - 使用epoll实现多路复用 */ #include <stdio.h> // 标准输入输出函数库 #include <stdlib.h> // 标准库函数&#xff0c;包含exit等 #include <string.h> // 字符串处理函数 #include <unistd.h> // Unix标准函…

元数据管理与数据治理平台:Apache Atlas 通知和业务元数据 Notifications And Business Metadata

文中内容仅限技术学习与代码实践参考&#xff0c;市场存在不确定性&#xff0c;技术分析需谨慎验证&#xff0c;不构成任何投资建议。Apache Atlas 框架是一套可扩展的核心基础治理服务&#xff0c;使企业能够有效、高效地满足 Hadoop 中的合规性要求&#xff0c;并支持与整个企…

rem:CSS中的相对长度单位

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》 &#x1f35a; 蓝桥云课签约作者、…

【10】C#实战篇——C# 调用 C++ dll(C++ 导出函数、C++导出类)

文章目录1 导出C 类函数 、导出 C函数1.1 .h文件1.2 .cpp 文件1.3 C# 调用2 C与C#数据类型对应3 保姆级教程&#xff08;项目搭建、代码、调用&#xff0c;图文并茂&#xff09;1 导出C 类函数 、导出 C函数 C 生成动态库.dll 详细教程&#xff1a; C 生成动态库.dll 及 C调用…

Flutter 与 Android NDK 集成实战:实现高性能原生功能

Flutter 与 NDK 集成实现 Flutter 可以通过 Platform Channels 与原生代码&#xff08;包括使用 NDK 编写的 C/C 代码&#xff09;进行交互。以下是实现 Flutter 与 NDK 集成的步骤&#xff1a; 基本步骤 1. 创建 Flutter 项目 flutter create flutter_ndk_example cd flutter_…

elementui cascader 远程加载请求使用 选择单项等

背景&#xff1a;小程序与后端使用自定义表单渲染视图。发现若没有全选&#xff08;如&#xff1a;省市县全部选择&#xff0c;指定的市3级&#xff09;在pc端就会无法渲染出已经选择的区县名称。 解决方案&#xff1a;参考官方文档&#xff0c;设置属性可独立勾选element ui c…

Unity WebGL打包后启动方法,本地方法

引言&#xff1a;常见WebGL开启方法常需要重新打包点击Build and Run或者将游戏放到Unity的云服务器上&#xff0c;作为开发者而言这两个方案一个为了开启再次打包&#xff0c;另一个直接放到了公开环境都不太合适。所以我们需要一个能在本地开启测试的WebGL的方法。 解决方案 …

安全引导功能及ATF的启动过程(五)

安全引导功能及ATF的启动过程&#xff08;五&#xff09; ATF中bl32的启动 bl31中的runtime_svc_init函数会初始化OP-TEE对应的服务&#xff0c;通过调用该服务项的初始化函数来完成OP-TEE的启动。对于OP-TEE的服务项会通过DECLARE_RT_SVC宏在编译时被存放到rt_svc_des段中。该…

Numpy科学计算与数据分析:Numpy入门之多平台安装与基础环境配置

Numpy环境搭建与基础操作 学习目标 本课程将指导学员在Windows、macOS和Linux三种操作系统上安装Numpy&#xff0c;并配置开发环境&#xff0c;包括使用Jupyter Notebook和Spyder等IDE的基本操作。通过本课程的学习&#xff0c;学员将能够独立搭建Numpy开发环境&#xff0c;并…

内存溢出的原因有哪些,如何排查线上问题?

1. java.lang.OutOfMemoryError: ......java heap space..... 堆栈溢出&#xff0c;代码问题的可能性极大 2. java.lang.OutOfMemoryError: GC over head limit exceeded 系统处于高频的GC状态&#xff0c;而且回收的效果依然 不佳的情况&#xff0c;就会开始报这个错误&…

Cesium 无人机视角飞行漫游,截屏

1.实现Cesium模拟无人机离屏渲染&#xff0c;无人机视角飞行漫游。视锥体显示 具体效果如下地址&#xff1a; 【CESIUM无人机视角飞行截屏】 https://www.bilibili.com/video/BV1zQ89zGE14/?share_sourcecopy_web&vd_source8239ec37df07d6a5d56c9ece00146783

vscode 打开设置

目录 方法 1&#xff08;快捷键&#xff09;&#xff1a; 方法2&#xff0c;界面操作&#xff0c;有时没有 方法 1&#xff08;快捷键&#xff09;&#xff1a; 按下&#xff1a;Cmd Shift P 输入并选择&#xff1a;Preferences: Open Settings (JSON) 方法2&#xff0c;…

繁花深处:花店建设的时代意义与多元应用—仙盟创梦IDE

花店当第一缕晨光透过花店的玻璃窗&#xff0c;落在带着露水的玫瑰花瓣上时&#xff0c;这个空间便不再只是商品交易的场所。花店作为城市肌理中充满生命力的细胞&#xff0c;承载着远比销售鲜花更丰富的社会意义。在快节奏的现代生活中&#xff0c;一束鲜花的绽放不仅是自然之…

AtomicStampedReference解决方案

1、通过引入版本戳(stamp)机制解决ABA问题&#xff1a; 每次修改时递增版本号执行CAS时同时检查值和版本号即使值相同但版本不同&#xff0c;操作也会失败2、具体代码实现 import java.util.concurrent.atomic.AtomicStampedReference;public class AtomicStampedReferenceDemo…

版本控制的详细说明介绍(已有github账号版)

说明 如果已经有一个GitHub账号,这是一个很好的起点!版本控制是一个帮助你管理代码或其他文件变化的工具,就像给你的项目加了一个“时间机器”,可以随时回溯历史、协作编辑,而不会乱套。下面我将从基础开始,层层展开说明。整个内容分为几个部分:介绍、原理、用途、操作…

基于Github Pages搭建个人博客站点:hexo环境搭建、本地预览与发布

步骤确认 Hexo 博客的源文件在哪里安装 Hexo 命令行工具&#xff1a;npm install -g hexo-cli在源文件目录中使用 hexo new "文章标题" 创建新文章编辑生成的 Markdown 文件使用 hexo generate 生成静态文件使用 hexo deploy 部署到这个 GitHub Pages 仓库设置Hexo博…

Shell脚本实现自动封禁恶意扫描IP

iptables 简介我们使用iptables工具实现功能iptables 是 Linux 系统上最常用的防火墙工具&#xff0c;可以指定策略。Shell文件创建首先我们先创建文件scanners.shvim /usr/local/bin/auto_block_ip.sh我的目标是每10分钟自动扫描&#xff0c;再10分钟内一个IP访问50次以上就就…

LeetCode_哈希表

哈希表&#xff08;散列表&#xff09;一、哈希表二、有效的字母异位词1、有效的字母异位词(力扣242)2、赎金信(力扣383)3、字母异位词分组(力扣49)4、找到字符串中所有字母异位词(力扣438)三、两个数组的交集1、两个数组的交集(力扣349)2、两个数组的交集 II(力扣350)三、其他…

2.变量和常量

1.变量2.2 变量的基本使用2.3 变量的本质 2.4 变量命名规则与规范 2.5 变量拓展-数组 1.数组的基本使用 2.常量

Java并发核心基础解析

目录 一、背景 二、Java线程模型 三、Synchronized实现原理 3.1 锁的使用 3.2 解释执行 3.3 JIT执行 3.4 锁的状态 3.5 monitorenter 3.5.1 偏向锁 3.5.2 轻量级锁 3.5.3 重量级锁 3.6 monitorexit 3.6.1 偏向锁 3.6.2 轻量级锁 3.6.3 重量级 四、可见性的真相…