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

lv8 嵌入式开发-网络编程开发 17 套接字属性设置

1 基本概念

  • 设置套接字的选项对套接字进行控制
  • 除了设置选项外,还可以获取选项
  • 选项的概念相当于属性,所以套接字选项也可说是套接字属性
  • 有些选项(属性)只可获取,不可设置;
  • 有些选项既可设置也可获取

2 选项的级别

一些选项都是针对一种特定的协议
一些选项适用于所有类型的套接字
选项级别(level)的概念

2.1 常用的级别

SOL_SOCKET该级别的选项只作用于套接字本身
SOL_LRLMP该级别的选项作用于IrDA协议
IPPROTO_IP该级别的选项作用于IPv4协议
IPPROTO_IPV6该级别的选项作用于IPv6协议
IPPROTO_RM该级别的选项作用于可靠的多播传输
IPPROTO_TCP该级别的选项适用于流式套接字
IPPROTO_UDP该级别的选项适用于数据报套接字

2.2 SOL_SOCKET的常用选项

选项名称说明获取/设置
SO_ACCEPTCONN套接字是否处于监听状态获取
SO_BROADCAST允许发送广播数据两者都可
SO_DEBUG允许调试两者都可
SO_DONTROUTE不查找路由两者都可
SO_ERROR获得套接字错误获取
SO_KEEPALIVE保活连接两者都可
SO_LINGER延迟关闭连接两者都可
SO_OOBINLINE带外数据放入正常数据流两者都可
SO_RCVBUF接收缓冲区大小两者都可
SO_SNDBUF发送缓冲区大小两者都可
SO_REUSERADDR允许重用本地地址和端口两者都可
SO_TYPE获得套接字类型获取

2.3 IPPROTO_IP级别的常用选项

选项名称说明获取/设置
IP_OPTIONS获取或设置IP头部内的选项两者都可
IP_HDRINCL是否将IP头部与数据一起提交给Winsock函数两者都可
IP_TTLIP TTL相关两者都可

3获取套接字选项

3.1 getsockopt函数

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);

参数
sockfd:套接字描述符
level:表示选项的级别
optname:表示要获取的选项名称
optval:指向存放接收到的选项内容的缓冲区
optlen:指向optval所指缓冲区的大小
函数返回值:
执行成功返回0,否则返回‒1errno来获取错误码
常见的错误码:
EBADF:参数sockfd不是有效的文件描述符
EFAULT:参数optlen太小或optval所指缓冲区非法
EINVAL:参数level未知或非法
ENOPROTOOPT:选项未知或不被指定的协议族所支持
ENOTSOCK:描述符不是一个套接字描述符

3.2 示例:获取流套接字和数据报套接字接收和发送的(内核)缓冲区大小

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>int main()
{int err,s = socket(AF_INET, SOCK_STREAM, 0);//创建流套接字if (s == -1) {printf("Error at socket()\n");return -1;}int su = socket(AF_INET, SOCK_DGRAM, 0); //创建数据报套接字if (s == -1) {printf("Error at socket()\n");return -1;}int optVal;int optLen = sizeof(optVal);//获取流套接字接收缓冲区大小if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&optVal,(socklen_t *)&optLen) == -1)printf("getsockopt failed:%d", errno);elseprintf("Size of stream socket receive buffer: %ld bytes\n", optVal);//获取流套接字发送缓冲区大小if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&optVal,(socklen_t *)&optLen) == -1)printf("getsockopt failed:%d", errno);else printf("Size of streaming socket send buffer: %ld bytes\n", optVal);//获取数据报套接字接收缓冲区大小if (getsockopt(su, SOL_SOCKET, SO_RCVBUF, (char*)&optVal,(socklen_t *)&optLen) == -1)printf("getsockopt failed:%d", errno);elseprintf("Size of datagram socket receive buffer: %ld bytes\n", optVal);//获取数据报套接字发送缓冲区大小if (getsockopt(su, SOL_SOCKET, SO_SNDBUF, (char*)&optVal,(socklen_t *)&optLen) == -1)printf("getsockopt failed:%d", errno);elseprintf("Size of datagram socket send buffer:%ld bytes\n", optVal);getchar();return 0;
}

3.3 示例:获取当前套接字类型

#include <stdio.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>int main()
{int err;int s = socket(AF_INET, SOCK_STREAM, 0); //创建流套接字if (s == -1) {printf("Error at socket()\n");return -1;}int su = socket(AF_INET, SOCK_DGRAM, 0); //创建数据报套接字if (s == -1) {printf("Error at socket()\n");return -1;}int optVal;int optLen = sizeof(optVal);//获取套接字s的类型if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&optVal, (socklen_t *)&optLen) == -1)printf("getsockopt failed:%d", errno);else{if (SOCK_STREAM == optVal) // SOCK_STREAM宏定义值为1printf("The current socket is a stream socket.\n"); //当前套接字是流套接字else if (SOCK_DGRAM == optVal) // SOCK_ DGRAM宏定义值为2printf("The current socket is a datagram socket.\n");//当前套接字是数据报套接字}//获取套接字su的类型if (getsockopt(su, SOL_SOCKET, SO_TYPE, (char*)&optVal, (socklen_t *)&optLen) == -1)printf("getsockopt failed:%d", errno);else{if (SOCK_STREAM == optVal)  // SOCK_STREAM宏定义值为1printf("The current socket is a stream socket.\n");else if (SOCK_DGRAM == optVal) // SOCK_ DGRAM宏定义值为2printf("The current socket is a datagram socket.\n");}getchar();return 0;
}

3.4 示例:判断套接字是否处于监听状态

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>typedef struct sockaddr Addr;
typedef struct sockaddr_in Addr_in;#define ErrExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)int main(int argc, char *argv[])
{Addr_in service;if(argc < 3){printf("%s[ADDR][PORT]\n", argv[0]);exit(0);}int s = socket(AF_INET, SOCK_STREAM, 0); //创建一个流套接字if (s == -1) ErrExit("socket");//允许地址的立即重用char on = 1;setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));service.sin_family = AF_INET;service.sin_addr.s_addr = inet_addr(argv[1]);service.sin_port = htons( atoi(argv[2]) );if (bind(s, (Addr*)&service, sizeof(service)) == -1) //绑定套接字ErrExit("bind");int optVal;int optLen = sizeof(optVal);//获取选项SO_ACCEPTCONN的值if (getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char*)&optVal, (socklen_t*)&optLen) == -1)printf("getsockopt failed:%d",errno);else printf("Before listening, The value of SO_ACCEPTCONN:%d, The socket is not listening\n", optVal);// 开始侦听if (listen(s, 100) == -1)ErrExit("listen");//获取选项SO_ACCEPTCONN的值if (getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char*)&optVal, (socklen_t*)&optLen) == -1)ErrExit("getsockopt");else printf("After listening,The value of SO_ACCEPTCONN:%d, The socket is listening\n", optVal);return 0;
}

4 设置套接字选项

4.1 setsockopt函数

int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

参数
sockfd:套接字描述符
level:表示选项的级别
optname:表示要获取的选项名称
optval:指向存放接收到的选项内容的缓冲区
optlen:指向optval所指缓冲区的大小
函数返回值:
执行成功返回0,否则返回‒1errno来获取错误码

4.2 示例:启用套接字的保活机制**

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>typedef struct sockaddr Addr;
typedef struct sockaddr_in Addr_in;#define ErrExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)int main(int argc, char *argv[])
{Addr_in service;if(argc < 3){printf("%s[ADDR][PORT]\n", argv[0]);exit(0);}int s = socket(AF_INET, SOCK_STREAM, 0); //创建一个流套接字if( s < 0)ErrExit("socket");char on = 1;setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));service.sin_family = AF_INET;service.sin_addr.s_addr = inet_addr(argv[1]);service.sin_port = htons(atoi(argv[2]));if (bind(s, (Addr *) &service, sizeof(service)) == -1) //绑定套接字ErrExit("bind");int optVal = 1;//一定要初始化int optLen = sizeof(int);//获取选项SO_KEEPALIVE的值if (getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char*)&optVal, (socklen_t *)&optLen) == -1)ErrExit("getsockopt");else printf("After listening,the value of SO_ACCEPTCONN:%d\n", optVal);optVal = 1;if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char*)&optVal, optLen) != -1)printf("Successful activation of keep alive mechanism.\n");//启用保活机制成功if (getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char*)&optVal, (socklen_t *)&optLen) == -1)ErrExit("getsockopt");else printf("After setting,the value of SO_KEEPALIVE:%d\n", optVal);return 0;
}

5 综合示例

server.c

#include "net.h"
#include <sys/select.h>
#define MAX_SOCK_FD 1024void setKeepAlive (int sockfd, int attr_on, socklen_t idle_time, socklen_t interval, socklen_t cnt)
{setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE, (const char *) &attr_on, sizeof (attr_on));setsockopt (sockfd, SOL_TCP, TCP_KEEPIDLE, (const char *) &idle_time, sizeof (idle_time));setsockopt (sockfd, SOL_TCP, TCP_KEEPINTVL, (const char *) &interval, sizeof (interval));setsockopt (sockfd, SOL_TCP, TCP_KEEPCNT, (const char *) &cnt, sizeof (cnt));
}int main(int argc, char *argv[])
{int i, ret, fd, newfd;fd_set set, tmpset;Addr_in clientaddr;socklen_t clientlen = sizeof(Addr_in);/*检查参数,小于3个 直接退出进程*/Argment(argc, argv);/*创建已设置监听模式的套接字*/fd = CreateSocket(argv);FD_ZERO(&set);FD_ZERO(&tmpset);FD_SET(fd, &set);while(1){tmpset = set;if( (ret = select(MAX_SOCK_FD, &tmpset, NULL, NULL, NULL)) < 0){perror("select");getchar();}if(FD_ISSET(fd, &tmpset) ){/*接收客户端连接,并生成新的文件描述符*/if( (newfd = accept(fd, (Addr *)&clientaddr, &clientlen) ) < 0){perror("accept");getchar();}
#if 1int keepAlive = 1;			//设定KeepAliveint keepIdle = 5;			//开始首次KeepAlive探测前的TCP空闭时间int keepInterval = 5;		//两次KeepAlive探测间的时间间隔int keepCount = 3;			//判定断开前的KeepAlive探测次数setKeepAlive (newfd, keepAlive, keepIdle, keepInterval, keepCount);
#endifprintf("[%s:%d]已建立连接\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));FD_SET(newfd, &set);}else{ //处理客户端数据for(i = fd + 1; i < MAX_SOCK_FD; i++){if(FD_ISSET(i, &tmpset)){if( DataHandle(i) <= 0){if( getpeername(i, (Addr *)&clientaddr, &clientlen) )perror("getpeername");printf("[%s:%d]断开连接\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));FD_CLR(i, &set);close(i);}}}}}close(fd);return 0;
}

socket.c

#include "net.h"void Argment(int argc, char *argv[]){if(argc < 3){fprintf(stderr, "%s<addr><port>\n", argv[0]);exit(0);}
}
int CreateSocket(char *argv[]){/*创建套接字*/int fd = socket(AF_INET, SOCK_STREAM, 0);if(fd < 0)ErrExit("socket");/*允许地址快速重用*/int flag = 1;if( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag) ) )perror("setsockopt");/*设置通信结构体*/Addr_in addr;bzero(&addr, sizeof(addr) );addr.sin_family = AF_INET;addr.sin_port = htons( atoi(argv[2]) );/*绑定通信结构体*/if( bind(fd, (Addr *)&addr, sizeof(Addr_in) ) )ErrExit("bind");/*设置套接字为监听模式*/if( listen(fd, BACKLOG) )ErrExit("listen");return fd;
}
int DataHandle(int fd){char buf[BUFSIZ] = {};Addr_in peeraddr;socklen_t peerlen = sizeof(Addr_in);if( getpeername(fd, (Addr *)&peeraddr, &peerlen) )perror("getpeername");int ret = recv(fd, buf, BUFSIZ, 0);if(ret < 0)perror("recv");if(ret > 0){printf("[%s:%d]data: %s\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port), buf);}return ret;
}

net.h

`#ifndef _NET_H_
#define _NET_H_#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>
#include <errno.h>typedef struct sockaddr Addr;
typedef struct sockaddr_in Addr_in;
#define BACKLOG 5
#define ErrExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while(0)void Argment(int argc, char *argv[]);
int CreateSocket(char *argv[]);
int DataHandle(int fd);#endif

通过wireshark查看设置keepalive的包
在这里插入图片描述

6 练习

编程实现带保活连接功能的TCP代码,要求开始首次KeepAlive探测前的TCP空闭时间为3秒,两次KeepAlive探测间的时间间隔为3次,判定断开前的KeepAlive探测次数为7次。提交代码和完成通信的截图
注意:部分操作系统需要添加额外头文件 netinet/tcp.h

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/tcp.h>#define MAX_SOCK_FD 1024
#define BACKLOG 5#define ErrExit(msg) do{perror(msg); exit(EXIT_FAILURE);} while(0)void SetKeepAlive(int sockfd,int attr_on, socklen_t idle_time, socklen_t interval, socklen_t cnt)
{setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (const char *) &attr_on, sizeof(attr_on));setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, (const char *) &idle_time, sizeof(idle_time));setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (const char *) &interval, sizeof(interval));setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (const char *) &cnt, sizeof(cnt));
}int DataHandle(int fd)
{char buf[BUFSIZ] = {};int ret;struct sockaddr_in peeraddr;socklen_t peerlen = sizeof(struct sockaddr_in);if(getpeername(fd, (struct sockaddr *)&peeraddr, &peerlen) )perror("getpeername");ret = recv(fd, buf, BUFSIZ, 0);if(ret < 0){perror("recv");}if( ret > 0){printf("[%s:%d]data: %s\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port), buf);}return ret;
}int main(int argc,char *argv[])
{int fd, new_fd, i ,ret;fd_set set, tmpset;struct sockaddr_in addr, client_addr;socklen_t clientlen = sizeof(client_addr);int flag = 1;if(argc < 3){printf("%s <addr> <port>\n",argv[0]);exit(0);}//create socketfd = socket(AF_INET, SOCK_STREAM, 0);if(fd < 0){ErrExit("socket");}//avoids the error of ports being occupiedif( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag) ) ){perror("setsockopt");}//init struct sockaddr_inmemset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons( atoi(argv[2]));if (inet_aton(argv[1], &addr.sin_addr) == 0){printf("Invalid address\n");exit(EXIT_FAILURE);}//bindif(bind(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) == -1){ErrExit("bind");}//listenif(listen(fd, BACKLOG) == -1){ErrExit("listen");}//selectFD_ZERO(&set);FD_ZERO(&tmpset);FD_SET(fd, &set);while(1){tmpset = set;if((ret =  select(MAX_SOCK_FD, &tmpset,NULL,NULL,NULL)) < 0){ErrExit("select");}if(FD_ISSET(fd, &tmpset) > 0){new_fd = accept(fd,(struct sockaddr *)&client_addr,&clientlen);if(new_fd < 0){perror("accept");}#if 1int keepAlive = 1;int keepIdle = 3;int keepInterval = 3;int keepCount = 7;SetKeepAlive(new_fd, keepAlive, keepIdle, keepInterval, keepCount);
#endif printf("[%s:%d]connected\n",inet_ntoa(client_addr.sin_addr),\ntohs(client_addr.sin_port));FD_SET(new_fd, &set);}else //if(FF_ISSET(fd, &tmpset < 0)  //handle client{for(i = fd + 1; i < MAX_SOCK_FD; i++){// can readif(FD_ISSET(i,&tmpset)){if(DataHandle(i) <= 0){if(getpeername(i,(struct sockaddr *)&client_addr,&clientlen))			perror("getpeername");printf("[%s:%d]disconnected\n",inet_ntoa(client_addr.sin_addr),\ntohs(client_addr.sin_port));FD_CLR(i,&set);  }}}}}close(fd);return 0;
}

相关文章:

lv8 嵌入式开发-网络编程开发 17 套接字属性设置

1 基本概念 设置套接字的选项对套接字进行控制除了设置选项外&#xff0c;还可以获取选项选项的概念相当于属性&#xff0c;所以套接字选项也可说是套接字属性有些选项&#xff08;属性&#xff09;只可获取&#xff0c;不可设置&#xff1b;有些选项既可设置也可获取 2 选项…...

VulnHub Alice

一、信息收集 发现开发了22、80 2.访问ip&#xff0c;右击查看源代码 发现需要利用X-Forwarded-For 火狐插件&#xff1a;X-Forwarded-For Header 挂上代理后&#xff1a; 出现以下页面&#xff1a; 先注册一个账户&#xff0c;然后再登录 发现有参数进行传参 发现传参&a…...

AUTOSAR组织发布20周年纪念册,东软睿驰NeuSAR列入成功案例

近日&#xff0c;AUTOSAR组织在成立20周年之际发布20周年官方纪念册&#xff08;20th Anniversary Brochure&#xff09;&#xff0c;记录了AUTOSAR组织从成立到今天的故事、汽车行业当前和未来的发展以及AUTOSAR 伙伴关系和合作在重塑汽车方面的作用。东软睿驰提报的基于AUTOS…...

转行网络安全是否可行?

一、前言 其实很多的IT大佬之前也不是专门学计算机的&#xff0c;都是后期转行的。而且大学学什么专业&#xff0c;对后期的工作真的没有太大关系&#xff0c;这也是现在高校的教育现状。有80%的学生都是通过临时抱佛脚&#xff0c;考前冲刺拿到毕业证书的。下面就带大家详细分…...

netca_crypto.dll找不到怎么修复?详细解决办法和注意事项

当你在使用计算机时&#xff0c;突然出现了一个错误提示&#xff1a;“netca_crypto.dll 找不到”。不知道该如何解决这个问题&#xff1f;其实要解决是非常的简单的&#xff0c;今天我们将为你提供几种修复 netca_crypto.dll 找不到的解决方法和一些注意事项。在深入探讨修复方…...

axios的请求中断和请求重试

请求中断 场景&#xff1a;1、假如一个页面接口太多、或者当前网络太卡顿、这个时候跳往其他路由&#xff0c;当前页面可以做的就是把请求中断掉&#xff08;优化&#xff09;2、假如当前接口调取了第一页数据&#xff0c;又调去了第二页的数据&#xff0c;当我们调取第二页数…...

视频怎么压缩?视频太大这样处理变小

在当今时代&#xff0c;视频已经成为了我们日常生活中不可或缺的一部分&#xff0c;然而&#xff0c;视频文件往往非常大&#xff0c;给我们的存储和传输带来了很大的不便&#xff0c;那么&#xff0c;如何有效地压缩视频呢&#xff1f; 一、使用压缩软件 首先我们给大家分享一…...

【MATLAB源码-第48期】基于matlab的16QAM信号盲解调仿真。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 16QAM (16个象限幅度调制) 是一种广泛使用的数字调制技术。在无线和有线通信系统中&#xff0c;为了在固定的带宽内发送更多的信息&#xff0c;高阶调制如16QAM被使用。下面是16QAM盲解调的基本步骤、优缺点及应用场景。 16Q…...

自我介绍思考

1.引导面试官有重点的看你简历 2.在引导部分暗示他我是最适合这个岗位的 面试官在考察什么&#xff1f; a.你的表述是否一致b.考察你的语言表达能力&#xff0c;逻辑思维能力&#xff0c;总结概括能力c.考察你对现场的把控能力d.对时间的把控能力 怎么做&#xff1f; 1.写逐…...

华为eNSP配置专题-VLAN和DHCP的配置

文章目录 华为eNSP配置专题-VLAN和DHCP的配置1、前置环境1.1、宿主机1.2、eNSP模拟器 2、基本环境搭建2.1、基本终端构成和连接 3、VLAN的配置3.1、两台PC先配置静态IP3.2、交换机上配置VLAN 4、接口方式的DHCP的配置4.1、在交换机上开启DHCP4.2、在PC上开启DHCP 5、全局方式的…...

微服务11-Sentinel中的授权规则以及Sentinel服务规则持久化

文章目录 授权规则自定义异常结果规则持久化实现Push模式 授权规则 根据来源名称对请求进行拦截 ——>我们需要解析来源名称&#xff08;RequestOriginParser默认解析都为default&#xff09;&#xff0c;所以我们要自定义一个实现类&#xff08;根据请求头解析&#xff0c…...

私有化部署AI智能客服,解放企业成本,提升服务效率

在信息时代&#xff0c;企业面临着服务效率提升和成本压力的双重挑战。作为一个领先品牌&#xff0c;WorkPlus致力于为企业提供私有化部署的AI智能客服解决方案。本文将深入探讨WorkPlus AI智能客服如何帮助企业解放成本、提升服务效率以及打造个性化的卓越客户体验。 AI智能客…...

docker数据卷+挂载(命令讲解+示例)

在容器中管理数据主要有两种方式&#xff1a; 数据卷&#xff08;Volumes&#xff09; 、挂载主机目录 (Bind mounts)。 一、数据卷 数据卷是一个可供一个或多个容器使用的特殊目录&#xff0c;可以在容器之间共享和重用。 特点&#xff1a; 对 数据卷 的修改会立马生效对 …...

【webrtc 】FEC 1: 音频RED rfc2198及视频ULPFEC的RED封装

1 参考和引用 M79 代码。 ULPFEC报文构建流程 与大神的分析: WebRTC-FEC协议总结 一致 CrystalShaw 大神的文章 ULPFEC在WebRTC中的实现 WebRTC研究:FEC之RED封装 本文是大神们文章和代码的学习笔记。red封包(rfc2189)1.1 RED(Redundant Coding) 封装 Ulpfec 非均等保护前向纠…...

【Qt】Qt再学习(十七):QThread、QMutex、QTimer

1、QThread 1.1 简介 QThread实现了跨平台的方式来管理线程。一个QThread对象管理一个线程。 1.2 创建线程方法 1)使用QObject::moveToThread()函数将工作对象移动到线程中,该对象的槽函数将在新线程中运行,其它函数还在父线程中运行。 参见本人博客《【Qt】QObject::mo…...

scratch身高统计 2023年9月中国电子学会图形化编程 少儿编程 scratch编程等级考试三级真题和答案解析

目录 scratch身高统计 一、题目要求 1、准备工作 2、功能实现 二、案例分析...

SpringBoot面试题4:Spring Boot 支持哪些日志框架?推荐和默认的日志框架是哪个?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:Spring Boot 支持哪些日志框架?推荐和默认的日志框架是哪个? Spring Boot支持多种日志框架,包括以下几种: Logback:Logback 是一个快速、灵活…...

Git 常用命令汇总

导言 如果你是新手小白&#xff0c;完全不懂git&#xff0c;可以先看这一篇 github 详细教程 本文仅适用于对 git 操作已经有了一定掌握的用户&#xff0c;本文的目的在于将常用命令统一梳理记录&#xff0c;便于查阅。 干货 克隆指定分支&#xff1a;git clone -b <branc…...

最好的开放式蓝牙耳机有哪些?排名前五的开放式耳机五强

越来越多的人开始选择蓝牙耳机作为他们的音频解决方案。蓝牙耳机市场提供了各式各样的选择&#xff0c;不仅有常见的头戴式、耳塞式和半入耳式&#xff0c;还有一种备受欢迎的"开放式耳机"。今天&#xff0c;我将向大家介绍一些优秀的开放式蓝牙耳机款式&#xff0c;…...

docker-machine常用

docker-machine常用 什么是Docker Machine&#xff1f;Docker Machine默认支持的驱动安装kvm驱动 安装和配置Docker Machine环境准备node1安装Dockernode1安装Docker Machine为Docker Machine安装自动补全为Docker Machine准备boot2docker.iso镜像为node2创建machine主机 管理远…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三&#xff0c;HubSpot宣布已构建与ChatGPT的深度集成&#xff0c;这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋&#xff0c;但同时也存在一些关于数据安全的担忧。 许多网络声音声称&#xff0c;这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存&#xff1a;一级缓存、二级缓存 默认情况下&#xff0c;只有一级缓存开启&#xff08;sqlSession级别的缓存&#xff09;二级缓存需要手动开启配置&#xff0c;需要局域namespace级别的缓存 一级缓存&#xff08;本地缓存&#…...