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

frameworks 之Socket

frameworks 之Socket

  • Socket
    • 服务端
      • 1.创建Socket。
      • 2.绑定socket
      • 3.监听socket
      • 4.等待客户端连接
      • 5.读取或者写入给客户端
    • 客户端
      • 1.创建Socket。
      • 2.连接服务端Socket
      • 3.读取或者写入给客户端
      • 4.关闭socket
    • 演示代码
  • Epoll
    • 创建Epoll
    • 添加或删除Epoll
    • 等待消息返回Epoll
    • 演示代码
  • SocketPair
    • 创建socketPair
    • 设置对应的属性
    • 演示代码

Socket是应用层与TCP/IP协议族通信的中间软件抽象层。他作为Android 进程间的通信。
涉及到的类如下

  • frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

Socket

创建一个socket 需要几个步骤
服务端: socket -> bind -> listen -> accept -> read/write -> close
客户端: socket -> connect -> read/write -> close

服务端

1.创建Socket。

第一个参数为协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL**(或称AF_UNIX,Unix域socket,这个是我们的讲解重点)**、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址

第二个参数 指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET

第三个参数为 指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。

int socketFd = socket(SOCKET_DOMIAN, SOCKET_TYPE, SOCKET_PROTOCOL);

2.绑定socket

bind()函数就是将给这个描述字绑定一个名字。addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同。addrlen:对应的是地址的长度。

int bindResult = bind(socketFd,  (struct sockaddr *)&serviceAddr, serviceLen);

地址为抽象和文件类型。文件类型会生成一个文件在本地,抽象需要在地址前面加0,对应会生成@开头。可以用如下命令查询查看

netstat -an | grep 地址名称

3.监听socket

设置监听的最大连接个数

int listenerResult = listen(socketFd, SOCKET_NUMBER);

4.等待客户端连接

传入客户端的对象 和长度 由内核写入。等待客户端的连接。

int connectFd = accept(socketFd, (struct sockaddr *)&clientAddr, &clintLen);

5.读取或者写入给客户端

通过 read 或者 write 函数跟客户端通信

		   int dataSize = read(connectFd, &buffer, sizeof(buffer));if (dataSize == 0){printf("客户端关闭连接\n");} else if (dataSize == -1){printf("读取异常\n");exit(1);} else {printf("客户端发送了: %s\n" ,buffer);for (int i = 0; i < sizeof(buffer); i++){buffer[i] = toupper(buffer[i]);}write(connectFd, buffer, sizeof(buffer));}

客户端

1.创建Socket。

int serviceFd = socket(SOCKET_DOMIAN, SOCKET_TYPE, SOCKET_PROTOCOL);

2.连接服务端Socket

发起对服务端的连接,连接成功后 服务端 accept 方法将继续执行

int connectResult = connect(serviceFd, (struct sockaddr *)&clientAddr, clientLen);

3.读取或者写入给客户端

		int wirteResult = write(serviceFd, winBuffer, sizeof(winBuffer));printf("写入服务端数据 %i", wirteResult);// 阻塞读取服务端数据int readResult =read(serviceFd, winBuffer, sizeof(winBuffer));

4.关闭socket

close(serviceFd);

演示代码

服务端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// scoket相关
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>// 协议域
int SOCKET_DOMIAN = AF_UNIX;
// 类型
int SOCKET_TYPE = SOCK_STREAM;
// 协议,常用tcp udp
int SOCKET_PROTOCOL = 0;
// SOCKETD地址
#define SOCKET_SERVICE_ADDRESS "natvie_socket_test"
// 允许连接的长度
#define SOCKET_NUMBER 20
// 读取数据大小
#define BUFFER_SZIE 80/*** 主文件入口
*/
int main (void) {// socket 文件描述符int socketFd;// 客户端的socket 文件描述符int clintSocetFd;// socket 实体类struct sockaddr_un serviceAddr, clientAddr;// 地址长度socklen_t serviceLen; socklen_t clintLen;// 数据读取char buffer[BUFFER_SZIE];// 创建socketsocketFd = socket(SOCKET_DOMIAN, SOCKET_TYPE, SOCKET_PROTOCOL);if (socketFd == -1){printf("创建 socket 失败\n");exit(1);}// 清空memset(&serviceAddr, 0 ,sizeof(sockaddr_un));serviceAddr.sun_family = AF_UNIX;// 设置地址strncpy(serviceAddr.sun_path, SOCKET_SERVICE_ADDRESS, sizeof(serviceAddr.sun_path) - 1);// 计算长度serviceLen = sizeof(serviceAddr.sun_family) + sizeof(serviceAddr.sun_path);// 绑定地址int bindResult = bind(socketFd,  (struct sockaddr *)&serviceAddr, serviceLen);if (bindResult == -1){printf("绑定 socket 失败\n");exit(1);}// 绑定成功后 需要监听int listenerResult = listen(socketFd, SOCKET_NUMBER);if (listenerResult == -1){printf("监听 socket 失败\n");exit(1);}printf("服务端 socket建立 等待连接\n");// 死循环等待连接while (1){// 等待接收客户端连接, 同时客户端的信息会写入该类, 会阻塞在这里clintLen = sizeof(struct sockaddr_un);int connectFd = accept(socketFd, (struct sockaddr *)&clientAddr, &clintLen);if (connectFd == -1) {printf("监听 socket 失败\n");exit(1);}// 创建成功,循环读取消息while (1){// 0 为关闭 -1 为异常int dataSize = read(connectFd, &buffer, sizeof(buffer));if (dataSize == 0){printf("客户端关闭连接\n");} else if (dataSize == -1){printf("读取异常\n");exit(1);} else {printf("客户端发送了: %s\n" ,buffer);for (int i = 0; i < sizeof(buffer); i++){buffer[i] = toupper(buffer[i]);}write(connectFd, buffer, sizeof(buffer));}}}// 退出for循环 关闭socketprintf("服务端关闭连接\n");close(socketFd);return 0;
}

客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// scoket相关
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>// 协议域
int SOCKET_DOMIAN = AF_UNIX;
// 类型
int SOCKET_TYPE = SOCK_STREAM;
// 协议,常用tcp udp
int SOCKET_PROTOCOL = 0;
// SOCKETD地址
#define SOCKET_SERVICE_ADDRESS "natvie_socket_test"
// 允许连接的长度
#define SOCKET_NUMBER 20
// 读取数据大小
#define BUFFER_SZIE 80
// 输入最大行
#define MAXLINE 80int main(void) {// 客户端操作符int serviceFd;sockaddr_un clientAddr;// 地址长度socklen_t clientLen;// 从输入框输入流char winBuffer[BUFFER_SZIE];serviceFd = socket(SOCKET_DOMIAN, SOCKET_TYPE, SOCKET_PROTOCOL);if (serviceFd == -1){printf("创建 socket 失败");exit(0);}// 清空数据memset(&clientAddr, 0, sizeof(struct sockaddr_un));// 赋值地址clientAddr.sun_family = AF_UNIX;strncpy(clientAddr.sun_path, SOCKET_SERVICE_ADDRESS, sizeof(clientAddr.sun_path) - 1);clientLen = sizeof(clientAddr);printf("socket地址: %s\n", clientAddr.sun_path);int connectResult = connect(serviceFd, (struct sockaddr *)&clientAddr, clientLen);if (connectResult == -1){perror("连接 socket 失败");exit(0);}printf("请输入对应的数据:");while (fgets(winBuffer, MAXLINE, stdin)){// 把读到的数据给服务端int wirteResult = write(serviceFd, winBuffer, sizeof(winBuffer));printf("写入服务端数据 %i", wirteResult);// 阻塞读取服务端数据int readResult =read(serviceFd, winBuffer, sizeof(winBuffer));if (readResult <= 0) {  printf("服务端异常或者已关闭\n");break;}else {  printf("接收到服务端的消息: %s \n",winBuffer);}printf("请输入对应的数据:");}close(serviceFd);return 0;   
}

Epoll

上面提到的socket 的 accept 和 read 等方法都是阻塞方法,等多客户端无法实现实时的读取和监听,如果每个客户端开对应的线程则比较耗资源。因此有了Epoll 等待唤醒。Epoll 有如下方法。

创建Epoll

需要传入一个数量,该数量大于0即可。并会返回一个文件描述符

// 创建 epoll, 参数size 实际没作用,但是要大于0 
int epollFd = epoll_create(EPOLL_SZIE);

添加或删除Epoll

第二参数控制 添加还是删除
第三个参数为需要监听的文件操作符
第四个参数为 epoll_event 类型
data.fd 可以存储对应的文件ID
events属性表示数据类型 EPOLLIN

 int addResult = epoll_ctl(epollFd, EPOLL_CTL_ADD, serviceFd, &epollEvent); 

等待消息返回Epoll

events参数传入事件数组,内核会对应写入的数组。可通过 events.data.fd 获取对应的客户端。
size 表示每次可以处理的最大事件数量
最后参数代表等待的事件,0为马上返回,-1为阻塞等待

 int eventNum = epoll_wait(epollFd, events, EPOLL_EVENT_MAX_SZIE, EPOLL_TIEM_OUT);

演示代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// scoket相关
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
// epoll 相关
#include <sys/epoll.h>// 协议域
int SOCKET_DOMIAN = AF_UNIX;
// 类型
int SOCKET_TYPE = SOCK_STREAM;
// 协议,常用tcp udp
int SOCKET_PROTOCOL = 0;
// SOCKETD地址
#define SOCKET_SERVICE_ADDRESS "epoll_socket_test"
// 允许连接的长度
#define SOCKET_NUMBER 20
// 读取数据大小
#define BUFFER_SZIE 80
// epoll大小
#define EPOLL_SZIE 80
// epoll消息大小
#define EPOLL_EVENT_MAX_SZIE 20
// epoll消息超时
#define EPOLL_TIEM_OUT -1// 采用抽象作用域
int main(void) {int serviceFd;sockaddr_un serviceAddr;socklen_t serviceLen, clientLen;char buffer[BUFFER_SZIE];serviceFd = socket(SOCKET_DOMIAN, SOCKET_TYPE, SOCKET_PROTOCOL);if (serviceFd == -1) {perror("创建 socket 失败");exit(0);}memset(&serviceAddr, 0 , sizeof(struct sockaddr) - 1);serviceAddr.sun_family = AF_UNIX;// 这里采用抽象的协议, 第一位要给0serviceAddr.sun_path[0] = 0;strcpy(serviceAddr.sun_path + 1, SOCKET_SERVICE_ADDRESS);// serviceLen = sizeof(serviceAddr.sun_family) + strlen(SOCKET_SERVICE_ADDRESS) + 1;serviceLen = sizeof(serviceAddr.sun_family) + sizeof(serviceAddr.sun_path);printf("绑定的地址为:%s \n", serviceAddr.sun_path);// 绑定int bindResult = bind(serviceFd, (struct sockaddr *)&serviceAddr, serviceLen);if (bindResult == -1) {perror("绑定 socket 失败");exit(0);}int listenResult = listen(serviceFd, SOCKET_NUMBER);if (listenResult == -1) {perror("监听 socket 失败");exit(0);}// 创建 epoll, 参数size 实际没作用,但是要大于0 int epollFd = epoll_create(EPOLL_SZIE);if (epollFd == -1){perror("创建 epoll 失败");exit(0);}// 将对应的文件夹 添加 epoll中epoll_event epollEvent;/* *** 注意****epoll_data 是一个联合体结构成员,所有的成员公用一段内存,因此实际上只能保留一个成员它只会保存最后一个被赋值的成员,所以不要data.fd,data.ptr都赋值*/epollEvent.data.fd = serviceFd;epollEvent.events = EPOLLIN;// 循环检测 委托内核去处理// 当内核检测到事件到来时会将事件写到这个结构体数组里struct epoll_event events[EPOLL_EVENT_MAX_SZIE];int addResult = epoll_ctl(epollFd, EPOLL_CTL_ADD, serviceFd, &epollEvent); if (addResult == -1){perror("添加到 epoll 失败");exit(0);}printf("开始接收消息\n");while (1){// 等待有没消息返回// tiemOut 为0 马上返回 为-1 代表阻塞// maxevents:表示每次能处理的最大事件数,告之内核这个events有多大;这个maxevents的值不能大于创建epoll_create()时的size;int eventNum = epoll_wait(epollFd, events, EPOLL_EVENT_MAX_SZIE, EPOLL_TIEM_OUT);printf("收到消息数量: %i \n", eventNum);for (int i = 0; i < eventNum; i++){// 有连接请求到来,走到这里if (events[i].data.fd == serviceFd){// 客户端信息填充struct sockaddr_un clientAddr;socklen_t clientLen = sizeof(clientAddr);int connectFd = accept(serviceFd, (struct sockaddr *)&clientAddr, &clientLen);if (connectFd == -1){perror("接收客户端失败");exit(0);}printf("接收到新的客户端\n");//将用于通信的文件描述符挂到epoll树上epollEvent.data.fd = connectFd;epollEvent.events = EPOLLIN;epoll_ctl(epollFd, EPOLL_CTL_ADD, connectFd, &epollEvent);} else{// 其他的为客户端发送的值// 通信也有可能是写事件if (events[i].events & EPOLLOUT){//这里先忽略写事件continue;}char buf[1024]={0};int count = read(events[i].data.fd, buf, sizeof(buf));if (count == 0){// 关闭了客户端要关闭printf("收到客户端关闭");close(events[i].data.fd);epoll_ctl(epollFd, EPOLL_CTL_DEL, events[i].data.fd, NULL);continue;}if (count == -1){perror("接收消息异常退出");exit(0);}printf("收到了消息事件:%s \n", buf);for (int i = 0; i < sizeof(buf); i++){buf[i] = toupper(buf[i]);}write(events[i].data.fd, buf, sizeof(buf));}}}close(serviceFd);return 0;
}

SocketPair

如果是单纯1对1通讯,可通过 socketPair 快速建立服务端和客户端

创建socketPair

创建一个数组存储对应的ID,创建的socket 会放在该数组里面

int socketFds[2];
// 创建socke 第一个作为服务端 第二个作为客户端
int result = socketpair(SOCKET_DOMIAN, SOCKET_TYPE, SOCKET_PROTOCOL, socketFds);

设置对应的属性

以下代码设置对应的缓冲区

socklen_t len = sizeof(BUFFER_SZIE);
setsockopt(socketFds[0], SOL_SOCKET, SO_SNDBUF, &BUFFER_SZIE, len);
setsockopt(socketFds[0], SOL_SOCKET, SO_RCVBUF, &BUFFER_SZIE, len);
setsockopt(socketFds[1], SOL_SOCKET, SO_SNDBUF, &BUFFER_SZIE, len);
setsockopt(socketFds[1], SOL_SOCKET, SO_RCVBUF, &BUFFER_SZIE, len);

演示代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include <sys/types.h>
#include <sys/socket.h>#include <unistd.h>// 协议域
int SOCKET_DOMIAN = AF_UNIX;
// 类型
int SOCKET_TYPE = SOCK_STREAM;
// 协议,常用tcp udp
int SOCKET_PROTOCOL = 0;
// 缓存区大小
int BUFFER_SZIE = 1024;int main(void) {int socketFds[2];// 创建socke 第一个作为服务端 第二个作为客户端int result = socketpair(SOCKET_DOMIAN, SOCKET_TYPE, SOCKET_PROTOCOL, socketFds);if (result == -1){perror("创建 socketPair 错误");exit(0);}/*** 第一个参数socket是套接字描述符。* 第二个参数level是被设置的选项的级别,如果想要在套接字级别上设置选项,就必须把level设置为 SOL_SOCKET。* option_name指定准备设置的选项,option_name可以有哪些取值,这取决于level,在套接字级别上(SOL_SOCKET)* 主要设置缓存区大小*/socklen_t len = sizeof(BUFFER_SZIE);setsockopt(socketFds[0], SOL_SOCKET, SO_SNDBUF, &BUFFER_SZIE, len);setsockopt(socketFds[0], SOL_SOCKET, SO_RCVBUF, &BUFFER_SZIE, len);setsockopt(socketFds[1], SOL_SOCKET, SO_SNDBUF, &BUFFER_SZIE, len);setsockopt(socketFds[1], SOL_SOCKET, SO_RCVBUF, &BUFFER_SZIE, len);int pid = fork();printf("孵化出来的进程号为 %i \n", pid);// 在子进程为0if (!pid){printf("执行子进程\n");// 为子进程close(socketFds[0]);int count = 0;while (1){// 休眠一秒sleep(1);// 发送给服务端端write(socketFds[1], &count, sizeof(count));int size = read(socketFds[1], &count, sizeof(count));printf("收到服务端数据 %i \n", count);++count;}} else {printf("执行父进程\n");// 为父进程close(socketFds[1]);int count = 0;while (1){   // 读取客户端数据int size = read(socketFds[0], &count, sizeof(count));if (read <= 0){perror("客户端异常退出 \n");exit(0);}printf("收到客户端数据 %i \n", count);++count;// 发送给客户端write(socketFds[0], &count, sizeof(count));}}
}

相关文章:

frameworks 之Socket

frameworks 之Socket Socket服务端1.创建Socket。2.绑定socket3.监听socket4.等待客户端连接5.读取或者写入给客户端 客户端1.创建Socket。2.连接服务端Socket3.读取或者写入给客户端4.关闭socket 演示代码 Epoll创建Epoll添加或删除Epoll等待消息返回Epoll演示代码 SocketPair…...

WEB前端开发中如何实现大文件上传?

大文件上传是个非常普遍的场景&#xff0c;在面试中也会经常被问到&#xff0c;大文件上传的实现思路和流程。在日常开发中&#xff0c;无论是云存储、视频分享平台还是企业级应用&#xff0c;大文件上传都是用户与服务器之间交互的重要环节。随着现代网络应用的日益复杂化&…...

ts给vue中props设置指定类型

interface IBaseObject {[key: string | number]: any; }export default defineComponent({name:xx,props:{data:{type:Object as PropType<IBaseObject>,default:()>({}),required:true},}, })...

模拟实现c++中的list模版

☺☺☺☺☺☺☺☺☺☺ 点击 进入杀马特的主页☺☺​​​​​​​☺​​​​​​​☺​​​​​​​☺​​​​​​​☺​​​​​​​☺​​​​​​​☺​​​​​​​☺​​​​​​​☺ 目录 一list简述&#xff1a; 二库内常用接口函数使用&#xff1a; 1reverse(): 2.s…...

从信息论的角度看微博推荐算法

引言 在数字时代&#xff0c;推荐系统已成为社交媒体和其他在线服务平台的核心组成部分。它们通过分析用户行为和偏好&#xff0c;为用户提供个性化的内容&#xff0c;从而提高用户满意度和平台的参与度。推荐系统不仅能够增强用户体验&#xff0c;还能显著提升广告投放的效率…...

CISC(复杂指令集)与RISC(精简指令集)的区别

RISC(Reduced Instruction Set Computer)和CISC(complex instruction set computer)是当前CPU的两种架构。 它们的区别在于不同的CPU设计理念和方法。 早期的CPU全部是CISC架构&#xff0c;它的设计目的是要用最少的机器语言指令来完成所需的计算任务。比如对于乘法运算&#x…...

自定义数据库连接的艺术:Laravel中配置多数据库连接详解

自定义数据库连接的艺术&#xff1a;Laravel中配置多数据库连接详解 在现代Web应用开发中&#xff0c;经常需要连接到多个数据库。Laravel&#xff0c;作为PHP界最受欢迎的框架之一&#xff0c;提供了强大的数据库抽象层&#xff0c;支持多种数据库系统&#xff0c;并且允许开…...

力扣高频SQL 50题(基础版)第八题

文章目录 力扣高频SQL 50题&#xff08;基础版&#xff09;第八题1581. 进店却未进行过交易的顾客题目说明思路分析实现过程准备数据&#xff1a;实现方式&#xff1a;结果截图&#xff1a;总结&#xff1a; 力扣高频SQL 50题&#xff08;基础版&#xff09;第八题 1581. 进店…...

【C++20】从0开始自制协程库

文章目录 参考 很多人对协程的理解就是在用户态线程把CPU对线程的调度复制了一遍&#xff0c;减少了线程的数量&#xff0c;也就是说在一个线程内完成对协程的调度&#xff0c;不需要线程切换导致上下文切换的开销。但是线程切换是CPU行为&#xff0c;就算你的程序只有一个线程…...

Docker 深度解析:从入门到精通

引言 在当今的软件开发领域&#xff0c;容器化技术已经成为一种趋势。Docker 作为容器化技术的代表&#xff0c;以其轻量级、可移植性和易用性&#xff0c;被广泛应用于各种场景。本文将从 Docker 的基本概念入手&#xff0c;详细介绍 Docker 的安装、基本操作、网络配置、数据…...

[C++] 模板编程-02 类模板

一 类模板 template <class T或者typename T> class 类名 { .......... } 1.1 两种不同的实现 在以下的两种实现中,其实第一种叫做成员函数模板&#xff0c;并不能称为类模板因为这种实现,我们在调用时,并不需要实例化为Product这个类指定指定特定类型。 // 实现1 clas…...

嵌入式C++、STM32、树莓派4B、OpenCV、TensorFlow/Keras深度学习:基于边缘计算的实时异常行为识别

1. 项目概述 随着物联网和人工智能技术的发展,智能家居安全系统越来越受到人们的关注。本项目旨在设计并实现一套基于边缘计算的智能家居安全系统,利用STM32微控制器和树莓派等边缘设备,实时分析摄像头数据,识别异常行为(如入侵、跌倒等),并及时发出警报,提高家庭安全性。 系…...

C++ //练习 15.30 编写你自己的Basket类,用它计算上一个练习中交易记录的总价格。

C Primer&#xff08;第5版&#xff09; 练习 15.30 练习 15.30 编写你自己的Basket类&#xff0c;用它计算上一个练习中交易记录的总价格。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块&#xff1a; /********************…...

3个方法快速找回忘记的PDF文件密码

为确保PDF文件的重要信息不轻易外泄&#xff0c;很多人都会给PDF文件设置打开密码&#xff0c;但伴随着时间的推移&#xff0c;让我们忘记了原本设置的密码&#xff0c;但这时&#xff0c;我们又非常急需要打开编辑这份文件&#xff0c;这时我们该怎么办呢&#xff1f;下面小编…...

排序算法:选择排序,golang实现

目录 前言 选择排序 代码示例 1. 算法包 2. 选择排序代码 3. 模拟排序 4. 运行程序 5. 从大到小排序 循环细节 外层循环 内层循环 总结 选择排序的适用场景 1. 数据规模非常小 2. 稳定性不重要 3. 几乎全部数据已排序 4. 教育目的 前言 在实际场景中&#xf…...

【测试】博客系统的测试报告

项目背景 个人博客系统采用了 SSM 框架与 Redis 缓存技术的组合 &#xff0c;为用户提供了一个功能丰富、性能优越的博客平台。 在技术架构上 &#xff0c;SSM 框架确保了系统的稳定性和可扩展性。Spring 负责管理项目的各种组件 &#xff0c;Spring MVC 实现了清晰的请求处理…...

PointCLIP: Point Cloud Understanding by CLIP

Abstract 近年来&#xff0c;基于对比视觉语言预训练(CLIP)的零镜头和少镜头学习在二维视觉识别中表现出了令人鼓舞的效果&#xff0c;该方法在开放词汇设置下学习图像与相应文本的匹配。然而&#xff0c;通过大规模二维图像-文本对预训练的CLIP是否可以推广到三维识别&#x…...

搜索(剪枝)

定义&#xff1a; 剪枝&#xff0c;就是减少搜索树的规模、尽早排除搜索树中不必要分支的一种手段。 在深度优先搜索中&#xff0c;有以下几类常见的剪枝方法: 优化搜索顺序排除等效冗余可行性剪枝最优性剪枝记忆化剪枝 例题1&#xff1a;AcWing 167.木棒 题目&#xff1a;…...

python基础知识点

最近系统温习了一遍python基础语法&#xff0c;把自己不熟知的知识点罗列一遍&#xff0c;便于查阅~~ python教程 Python 基础教程 | 菜鸟教程 1、python标识符 以单下划线开头 _foo 的代表不能直接访问的类属性&#xff0c;需通过类提供的接口进行访问&#xff0c;不能用 f…...

Android SurfaceFlinger——GraphicBuffer获取内存信息(三十一)

上一篇文章介绍了 GraphicBuffer 初始化的 initWithSize() 函数中的申请内存流程,这里我们看一下另一个比较重要的函数,GraphicBufferMapper. getTransportSize 获取内存信息。该函数通常在需要了解缓冲区的实际内存占用情况时调用,例如在调试内存使用情况或优化性能时。 一…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...