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_TTL | IP 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,否则返回‒1,errno来获取错误码
常见的错误码:
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,否则返回‒1,errno来获取错误码
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 基本概念 设置套接字的选项对套接字进行控制除了设置选项外,还可以获取选项选项的概念相当于属性,所以套接字选项也可说是套接字属性有些选项(属性)只可获取,不可设置;有些选项既可设置也可获取 2 选项…...
VulnHub Alice
一、信息收集 发现开发了22、80 2.访问ip,右击查看源代码 发现需要利用X-Forwarded-For 火狐插件:X-Forwarded-For Header 挂上代理后: 出现以下页面: 先注册一个账户,然后再登录 发现有参数进行传参 发现传参&a…...
AUTOSAR组织发布20周年纪念册,东软睿驰NeuSAR列入成功案例
近日,AUTOSAR组织在成立20周年之际发布20周年官方纪念册(20th Anniversary Brochure),记录了AUTOSAR组织从成立到今天的故事、汽车行业当前和未来的发展以及AUTOSAR 伙伴关系和合作在重塑汽车方面的作用。东软睿驰提报的基于AUTOS…...
转行网络安全是否可行?
一、前言 其实很多的IT大佬之前也不是专门学计算机的,都是后期转行的。而且大学学什么专业,对后期的工作真的没有太大关系,这也是现在高校的教育现状。有80%的学生都是通过临时抱佛脚,考前冲刺拿到毕业证书的。下面就带大家详细分…...
netca_crypto.dll找不到怎么修复?详细解决办法和注意事项
当你在使用计算机时,突然出现了一个错误提示:“netca_crypto.dll 找不到”。不知道该如何解决这个问题?其实要解决是非常的简单的,今天我们将为你提供几种修复 netca_crypto.dll 找不到的解决方法和一些注意事项。在深入探讨修复方…...
axios的请求中断和请求重试
请求中断 场景:1、假如一个页面接口太多、或者当前网络太卡顿、这个时候跳往其他路由,当前页面可以做的就是把请求中断掉(优化)2、假如当前接口调取了第一页数据,又调去了第二页的数据,当我们调取第二页数…...
视频怎么压缩?视频太大这样处理变小
在当今时代,视频已经成为了我们日常生活中不可或缺的一部分,然而,视频文件往往非常大,给我们的存储和传输带来了很大的不便,那么,如何有效地压缩视频呢? 一、使用压缩软件 首先我们给大家分享一…...
【MATLAB源码-第48期】基于matlab的16QAM信号盲解调仿真。
操作环境: MATLAB 2022a 1、算法描述 16QAM (16个象限幅度调制) 是一种广泛使用的数字调制技术。在无线和有线通信系统中,为了在固定的带宽内发送更多的信息,高阶调制如16QAM被使用。下面是16QAM盲解调的基本步骤、优缺点及应用场景。 16Q…...
自我介绍思考
1.引导面试官有重点的看你简历 2.在引导部分暗示他我是最适合这个岗位的 面试官在考察什么? a.你的表述是否一致b.考察你的语言表达能力,逻辑思维能力,总结概括能力c.考察你对现场的把控能力d.对时间的把控能力 怎么做? 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模式 授权规则 根据来源名称对请求进行拦截 ——>我们需要解析来源名称(RequestOriginParser默认解析都为default),所以我们要自定义一个实现类(根据请求头解析,…...
私有化部署AI智能客服,解放企业成本,提升服务效率
在信息时代,企业面临着服务效率提升和成本压力的双重挑战。作为一个领先品牌,WorkPlus致力于为企业提供私有化部署的AI智能客服解决方案。本文将深入探讨WorkPlus AI智能客服如何帮助企业解放成本、提升服务效率以及打造个性化的卓越客户体验。 AI智能客…...
docker数据卷+挂载(命令讲解+示例)
在容器中管理数据主要有两种方式: 数据卷(Volumes) 、挂载主机目录 (Bind mounts)。 一、数据卷 数据卷是一个可供一个或多个容器使用的特殊目录,可以在容器之间共享和重用。 特点: 对 数据卷 的修改会立马生效对 …...
【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 常用命令汇总
导言 如果你是新手小白,完全不懂git,可以先看这一篇 github 详细教程 本文仅适用于对 git 操作已经有了一定掌握的用户,本文的目的在于将常用命令统一梳理记录,便于查阅。 干货 克隆指定分支:git clone -b <branc…...
最好的开放式蓝牙耳机有哪些?排名前五的开放式耳机五强
越来越多的人开始选择蓝牙耳机作为他们的音频解决方案。蓝牙耳机市场提供了各式各样的选择,不仅有常见的头戴式、耳塞式和半入耳式,还有一种备受欢迎的"开放式耳机"。今天,我将向大家介绍一些优秀的开放式蓝牙耳机款式,…...
docker-machine常用
docker-machine常用 什么是Docker Machine?Docker Machine默认支持的驱动安装kvm驱动 安装和配置Docker Machine环境准备node1安装Dockernode1安装Docker Machine为Docker Machine安装自动补全为Docker Machine准备boot2docker.iso镜像为node2创建machine主机 管理远…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
【WebSocket】SpringBoot项目中使用WebSocket
1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖,添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...
基于单片机的宠物屋智能系统设计与实现(论文+源码)
本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢,连接红外测温传感器,可实时精准捕捉宠物体温变化,以便及时发现健康异常;水位检测传感器时刻监测饮用水余量,防止宠物…...
Java后端检查空条件查询
通过抛出运行异常:throw new RuntimeException("请输入查询条件!");BranchWarehouseServiceImpl.java // 查询试剂交易(入库/出库)记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...
比特币:固若金汤的数字堡垒与它的四道防线
第一道防线:机密信函——无法破解的哈希加密 将每一笔比特币交易比作一封在堡垒内部传递的机密信函。 解释“哈希”(Hashing)就是一种军事级的加密术(SHA-256),能将信函内容(交易细节…...
