套接字选项、广播和多播

news2024/9/9 7:02:19

1. 套接字选项 (socket options)

每一个套接字 (socket)在不同的协议层次 (级别)上面有不同的行为属性 (选项)

我们可以设置 / 获取指定的套接字选项


getsockopt:获取套接字的选项
setsockopt:设置套接字的选项

NAME
    getsockopt, setsockopt - get and set options on sockets
SYNOPSIS
    #include <sys/types.h>
    #include <sys/socket.h>

// 获取套接字的选项
int getsockopt(int sockfd, int level, int optname,
                              void *optval, socklen_t *optlen);

// 设置套接字的选项,0:禁用   非0:使能(一般设置为1)
int setsockopt(int sockfd, int level, int optname,
                              const void *optval, socklen_t optlen);

sockfd:你要设置或者获取属性的套接字描述符
		
level:你要设置或者获取属性位于什么级别
		
optname:选项名称
		
optval:指针,指向一块空间
		    get:指向的空间用来保存获取到的值
			set:指向的空间用来保存需要设置的值,把指定的值设置到socket上面去
		
optlen:
	get:指针,调用前用来保存optval指向的空间的长度,调用后保存的是获取到的选项的实
         际大小(防止内存越界)
			
    set:变量,用来指定设定选项的选项值的长度
			
返回值:	
	成功返回0,
	失败返回-1,同时errno被设置

常用的几种套接字选项:

// Leve(级别):SOL_SOCKET
// optname(选项名):SO_BROADCAST
说明:允许发送 / 接收广播数据报
// 数据类型:int

// Leve(级别):SOL_SOCKET
// optname(选项名):SO_RCVBUF
说明:接收缓冲区大小
// 数据类型:int

// Leve(级别):SOL_SOCKET
// optname(选项名):SO_SNDBUF
说明:发送缓冲区大小
// 数据类型:int

// Leve(级别):SOL_SOCKET
// optname(选项名):SO_REUSEADDR
说明:允许重用本地地址
// 数据类型:int

// Leve(级别):SOL_SOCKET
// optname(选项名):SO_REUSEPORT
说明:允许重用本地端口
// 数据类型:int

// Leve(级别):IPPROTO_IP
// optname(选项名):IP_ADD_MEMBERSHIP
说明:加入多播组
// 数据类型:ip_mreq{}

// Leve(级别):IPPROTO_IP
// optname(选项名):IP_DROP_MEMBERSHIP
说明:离开多播组
// 数据类型:ip_mreq{}

练习一:获取指定套接字的接收缓冲区大小,并重新设置该套接字的接收缓冲区大小

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

int main() {

    // 申请一个套接字
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);	
	if (sockfd == -1) {
		perror("socket failed");
		return -1;
	}

	int buflen;
	socklen_t len = sizeof(buflen);

	// 获取接收缓冲区大小,每台机器接收缓冲区的大小都不一样
	int r = getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void *)&buflen, &len);
	if (r == 0) {
		printf("buflen = %d\n", buflen);
	}

	// 设置接收缓冲区大小
	// 注意:接收缓存区大小是你要设置的那个值的2倍,并且最小大小为2304
	// buflen = 1000; // 2000 < 2304,设置为2304
	// buflen = 2000; // 设置为4000
	buflen = 6600; // 设置为13200
	setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void *)&buflen, sizeof(buflen));
	
	// 获取
	len = sizeof(buflen);
	r = getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void *)&buflen, &len);
	if (r == 0) {
        printf("buflen = %d\n", buflen);
    }

    close(sockfd);
	return 0;
}

练习二:设置套接字选项,允许端口号重用

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>

int main() {

    // 申请一个套接字
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);	
	if (sockfd == -1) {
		perror("socket failed");
		return -1;
	}

	// 获取该套接字是否允许端口号重用
	int on;
	socklen_t len = sizeof(on);
	int r = getsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, &len);
	if (r == 0) {
		printf("on = %d\n", on);
	}

	// 设置该套接字允许端口号重用
	on = 1;
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof(on));
	
    printf("on = %d\n", on);

    close(sockfd);
	return 0;
}

2. 广播 (boardcast)

一对多的通信


a. 只有当传输层协议为UDP (SOCK_DGRAM)时,才支持广播功能
            TCP是端对端的连接,通信前需要进行三次握手建立连接
            广播是一对多的通信

b. 广播的地址问题,如果发送广播,网络地址是哪里呢?
            广播是向局域网中所有的主机发送信息
           
广播的地址是将IP地址中所有的主机号设置为1 (子网掩码取反 再和 IP地址 按位或运算)
            即: xxx.xxx.xxx.255
                例子:
                    你的IP:192.168.1.103
                    哪些是主机号你还不知道?
                    netmask:255.255.255.0    (前面一定是连续的1,后面是连续的0)
                    这个IP的局域网的广播地址是:192.168.1.255

                        

                    你的IP:192.168.1.103
                    哪些是主机号你还不知道?
                    netmask:255.255.0.0
                    这个IP的局域网的广播地址是:192.168.255.255

        

                    你的IP:192.168.1.103
                    哪些是主机号你还不知道?
                    netmask:255.255.128.0
                    这个IP的局域网的广播地址是:192.168.127.255


                    全网广播地址:255.255.255.255

                    但是这个没有意义,一般的路由器都不会转发这个数据包

            你把数据发送到广播地址上面,局域网内所有的用户都可以收到这个数据包


广播的编程思路 (流程):

        广播发送者:

                1. 创建一个套接字 (SOCK_DGRAM)

                        socket

                2. 设置套接字选项,使能发送广播

                        setsockopt

                3. 向一个局域网发送广播数据

                        广播地址 + 端口号

                        sendto

                4. 接收外界的消息   ----> 可以不要

                        recvfrom

                5. 关闭套接字

                        close

                        shutdown


        广播接收者:

                1. 创建一个套接字 (SOCK_DGRAM)

                        socket

                2. 设置套接字选项,使能接收广播

                        setsockopt

                3. 绑定地址

                        bind

                        绑定广播地址 (从哪一个局域网接收广播)

                        地址 + 端口号

                4. 接收广播数据

                        recvfrom()  ---> 没有数据会阻塞

                5. 向发送者发送数据   ---> 可以不要

                        sendto

                6. 关闭套接字

                        close

                        shutdown


代码实现:

boardcast_send.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[]) {

    if (argc != 3) {
        printf("argc num error\n");
        return -1;
    }

    // 1. 创建一个套接字 (SOCK_DGRAM)
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("boardcast_send socket failed");
        return -1;
    }

    // 2. 设置套接字选项,使能发送广播
    int enable= 1;
    setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (void *)&enable, sizeof(enable));

    // 需要一个网络地址,指定发给哪一个接收者
    struct sockaddr_in recvAddr;
    memset(&recvAddr, 0, sizeof(recvAddr));
    recvAddr.sin_family = AF_INET; // 协议族
    recvAddr.sin_port = htons(atoi(argv[2])); // 端口号
    recvAddr.sin_addr.s_addr = inet_addr(argv[1]); // IPV4地址

    // 当接收者发信息给我时,保存该接收者的网络地址
    struct sockaddr_in recv_addr;
    socklen_t addrlen = sizeof(recv_addr);

    while (1) {

        // 3. 向一个局域网发送广播数据
        char buf[250] = {0};
        scanf("%s", buf);
        int w = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&recvAddr, sizeof(recvAddr));
        printf("w = %d\n", w);

        if (buf[0] == '#') { // 退出条件
            break;
        }

        // 4. 可以接收外界的消息   ----> 可以不要
        // char buff[250] = {0};
        // int r = recvfrom(sockfd, buff, 250, 0, (struct sockaddr*)&recv_addr, &addrlen);
        // if (r > 0) {
        //     printf("r = %d, buff = %s\n", r, buff);
        //     printf("接收者 IP:%s, port:%d\n", inet_ntoa(recv_addr.sin_addr), ntohs(recv_addr.sin_port));
        // }
    }

    // 5. 关闭套接字
    close(sockfd);

    return 0;
}

boardcast_recv.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[]) {

    if (argc != 3) {
        printf("argc num error\n");
        return -1;
    }

    // 1. 创建一个套接字 (SOCK_DGRAM)
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("boardcast_send socket failed");
        return -1;
    }

    // 2. 设置套接字选项,使能接收广播
    int enable = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (void *)&enable, sizeof(enable));

    // 3. 绑定地址
    struct sockaddr_in recvAddr;
    memset(&recvAddr, 0, sizeof(recvAddr));
    recvAddr.sin_family = AF_INET; // 协议族
    recvAddr.sin_port = htons(atoi(argv[2])); // 端口号
    recvAddr.sin_addr.s_addr = inet_addr(argv[1]); // IPV4地址

    int res = bind(sockfd, (struct sockaddr *)&recvAddr, sizeof(recvAddr));
    if (res == -1) {
        perror("boardcast_send bind failed");
        close(sockfd);
        return -1;
    }
    
    // 当发送者发信息给我时,保存该发送者的网络地址
    struct sockaddr_in send_addr;
    socklen_t addrlen = sizeof(send_addr);

    while (1) {
        // 4. 接收广播数据
        char buf[250] = {0};
        int r = recvfrom(sockfd, buf, 250, 0, (struct sockaddr*)&send_addr, &addrlen);
        if (r > 0) {
            printf("r = %d, buf = %s\n", r, buf);
            printf("发送者 IP:%s,port:%d\n", inet_ntoa(send_addr.sin_addr), ntohs(send_addr.sin_port));
        }

        // 5. 向发送者发送数据   ---> 可以不要
    }

    // 6. 关闭套接字
    close(sockfd);

    return 0;
}

3. 多播 / 组播 (multicast)

单播用于两个主机之间端对端的通信,广播用于一个主机对整个局域网上所有的主机进行数据通信
单播和广播是两个极端

有时候,我们需要对一组特定的主机进行通信

=====>多播

        a. 多播也只有传输层协议为 UDP 时,才支持多播 (组播)功能

        b. 多播地址 ---> IPV4的D类地址

                224.0.0.0 ~ 239.255.255.255 之间的 IP地址  

                局部多播地址:224.0.0.0 ~ 224.0.0.255

                ===> (仅用于局域网通信),路由器不会转发此地址之间的数据包
                        
                预留的多播地址:224.0.1.0 ~ 238.255.255.255
        
                管理权限多播地址:239.0.0.0 ~ 239.255.255.255   类似于私有IP

相对于单播和广播,多播是属于一种折中的方式,只有某些加入多播组的主机才能收到数据

多播的编程思路:

        多播发送者

                1. 创建一个套接字 (SOCK_DGRAM)

                2. 发送消息到一个多播组地址

                        IP + 端口号

                        sendto

                3. 接收消息   ---> 可以不要

                4. 关闭套接字  close
        

        多播接收者

                1. 创建一个套接字 (SOCK_DGRAM)

                2. 加入一个多播组 (发送者发送的组号)

                3. 绑定地址   IP + 端口号

                        IP:多播组的地址

                        端口号

                4. 接收多播组的信息

                        recvfrom

                5. 发送信息到多播组  -----> 可以不要

                6. 关闭套接字

如何加入多播组示例代码:

struct ip_mreq {
    // 多播组的IP地址(D类地址)---> 类似于QQ群号
    struct in_addr imr_multiaddr;
	// 接口地址,多播数据包实际上经过哪一个网卡发送/接收
	struct in_addr  imr_address
}

struct in_addr {
    uint32_t  s_addr;  /* 32位IP地址 */
};


// 例子:把本机IP加入多播组 224.0.0.1		
struct ip_mreq mreq;
memset(&mreq, 0, sizeof(mreq));
mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.1"); // 多播组的IP地址mreq.imr_address.s_addr = inet_addr("172.4.1.5"); // 本地的IP地址
或者
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
// INADDR_ANY 让内核帮你随便选择一个网卡

// 使用setsockopt,加入指定的多播组中
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq,sizeof(mreq));

注意:要支持多播,需要设置路由表,让数据包从正确的网卡出去,而不是从默认网卡出去

         首先 ifconfig 查看本机 IP 和网卡名字 (第一行第一个,如:ens33,eth0,eth1 ......)

        
        sudo route add -net 224.0.0.0 netmask 240.0.0.0  ens33 // 加入路由表

        sudo route add default gw 172.4.1.1  dev ens33 // 设置默认网关

        

        查看内核的 IP 路由标

                route -n

代码实现:
multicast_send.c

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>

// 多播组号的IP和端口号通过命令行参数传递
int main(int argc, char *argv[]) {

    if (argc != 3) {
        printf("argc num error\n");
        return -1;
    }

    // 1.创建一个套接字(SOCK_DGRAM)
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("socked failed");
        return -1;
    }
	
    // 2.发送信息到一个多播组地址
    // 	IP+端口号
    // 	sendto
    struct sockaddr_in recvAddr;
    memset(&recvAddr, 0, sizeof(struct sockaddr_in));
    recvAddr.sin_family = AF_INET;
    recvAddr.sin_port = htons(atoi(argv[2]));
    recvAddr.sin_addr.s_addr = inet_addr(argv[1]);

    // 当接收者发信息给我时,保存该接收者的网络地址
    struct sockaddr_in recv_addr;
    socklen_t addrlen = sizeof(recv_addr);

    while (1) {
        char buf[250] = {0};
        scanf("%s", buf);
        int w = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&recvAddr, sizeof(recvAddr));

        printf("w = %d\n", w);

        if (buf[0] == '#') { // 退出条件
            break;
        }

        // 3. 接收消息   ---> 可以不要
        char buff[250] = {0};
        int r = recvfrom(sockfd, buff, 250, 0, (struct sockaddr *)&recv_addr, &addrlen);
        
        printf("发送者 IP:%s, port:%d\n", inet_ntoa(recv_addr.sin_addr), ntohs(recv_addr.sin_port));
        printf("r = %d, buff = %s\n", r, buff);
    }

    // 4.关闭套接字
    close(sockfd);

    return 0;
}

multicast_recv.c

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>

// 多播组号的IP和端口号通过命令行参数传递
int main(int argc, char *argv[]) {

	if (argc != 3) {
		printf("arg num error\n");
		return -1;
	}

	// 1.创建一个套接字(SOCK_DGRAM)
	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd == -1) {
		perror("socket failed\n");
		return -1;
	}

	// 2.加入一个多播组(发送者发送的组号)
	struct ip_mreq mreq;
	memset(&mreq, 0, sizeof(mreq));
	mreq.imr_multiaddr.s_addr = inet_addr(argv[1]); // 多播组的IP地址
	mreq.imr_interface.s_addr = htonl(INADDR_ANY); // 让内核随便选择一个网卡
	// mreq.imr_address.s_addr = inet_addr("172.4.1.5"); // 本地的IP地址
	int ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq));
	if (ret == -1) {
		perror("setsockopt failed");
		close(sockfd);
		return -1;
	}
	
	// 3.绑定地址  IP + 端口号
	struct sockaddr_in local;
	memset(&local, 0, sizeof(local));
	local.sin_family = AF_INET;
	local.sin_port = htons(atoi(argv[2])); // 端口号
	local.sin_addr.s_addr = inet_addr(argv[1]); // 多播组地址
	
	ret = bind(sockfd, (struct sockaddr *)&local, sizeof(local));
	if (ret == -1) {
		perror("bind failed");
		close(sockfd);
		return -1;
	}

	// 保存发送者网络地址
	struct sockaddr_in send_addr;
	socklen_t addrlen = sizeof(send_addr);

	while (1) {
		// 4.接收多播组的信息
		char buf[250] = {0};
		int r = recvfrom(sockfd, buf, 250, 0, (struct sockaddr *)&send_addr, &addrlen);
		
		printf("发送者 IP:%s, port:%d\n", inet_ntoa(send_addr.sin_addr), ntohs(send_addr.sin_port));
		printf("r = %d, buf:%s\n",r, buf);

		// 私发消息给发送者
		int w = sendto(sockfd, "received", strlen("received"), 0, (struct sockaddr *)&send_addr, sizeof(send_addr));
		printf("w = %d\n", w);

		sleep(3);

		// 5. 发送信息到多播组  ---> 可以不要
		w = sendto(sockfd, "okokok", strlen("okokok"), 0, (struct sockaddr *)&local, sizeof(local));
		printf("w = %d\n", w);
	}

	// 关闭套接字
	close(sockfd);
				
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[python] 启发式算法库scikit-opt使用指北

scikit-opt是一个封装了多种启发式算法的Python代码库&#xff0c;可以用于解决优化问题。scikit-opt官方仓库见&#xff1a;scikit-opt&#xff0c;scikit-opt官网文档见&#xff1a;scikit-opt-doc。 scikit-opt安装代码如下&#xff1a; pip install scikit-opt # 调用scik…

永结无间Ⅶ--具有知识图谱的高级 RAG

将知识图谱与先进的检索增强生成 (RAG) 策略相结合&#xff0c;以增强人工智能驱动的信息检索和生成 在增强 RAG 系统方面&#xff0c;知识图谱已成为改变游戏规则的因素。与传统矢量数据库不同&#xff0c;知识图谱提供丰富、互联的信息表示&#xff0c;可显著提高检索内容的…

Docker简介和Docker常见命令

目录 1. Docker 简介 1.1 Docker 的核心概念 1.2 Docker 的优势 1.3 Docker 工作流程 2. 常见命令 2.1 基本命令 2.2 镜像操作 2.3 容器操作 2.4 网络操作 2.5 卷操作 2.6 日志和监控 2.7 清理命令 3. 注意事项和最佳实践 3.1 镜像操作 3.2 容器操作 3.3 网络操…

18730 涂色问题

这个问题可以通过动态规划来解决。我们可以定义一个状态dp[i][j]&#xff0c;表示前i个牛舍中最后一个牛舍的颜色是j的涂色方案数量。然后我们可以通过状态转移方程来更新dp[i][j]。 状态转移方程如下&#xff1a; dp[i][j] dp[i-1][k] (k ! j) 然后我们需要对所有的dp[i][…

数据结构——排序(C语言版)

冒泡排序&#xff1a; 冒泡排序是一种简单直观的排序算法&#xff0c;其基本思想是多次遍历待排序数组&#xff0c;每次遍历时比较相邻的两个元素&#xff0c;如果它们的顺序不符合排序规则&#xff08;比如升序&#xff09;&#xff0c;则交换它们的位置&#xff0c;直到整个数…

Oracle数据库入门

目录 Oracle基础概念数据库安装连接Oracle查看当前用户 数据表的基本概念查看当前系统表Orcale函数单行函数多行函数/组函数/聚合函数 SQL语句DMLinsert批量插入数据创建新表在旧表中插入 delete全表删除 update DDLcreatealterdrop 连接 Oracle基础概念 数据库: 数据的仓库 以…

探索大模型的“心理理论”能力:TMBENCH基准测试

人工智能咨询培训老师叶梓 转载标明出处 心理理论是理解他人信念、意图、情感等心理状态的能力&#xff0c;对人类社会交往至关重要。近期研究引发了关于LLMs是否展现出ToM的辩论。然而&#xff0c;现有的评估方法受限于范围狭窄、主观判断和潜在的数据污染等问题&#xff0c;无…

万能DIY预约小程序源码系统 自由DIY 适合任何行业的在线预约小程序 带源代码包以及搭建部署教程

系统概述 随着移动互联网的发展&#xff0c;小程序作为一种轻量级应用&#xff0c;因其便捷性和易用性而受到广大用户的喜爱。各行各业都在积极探索如何利用小程序提升服务体验。小编给大家分享一款万能DIY预约小程序的源码系统&#xff0c;该系统支持自由定制&#xff0c;适用…

S3GCL Spectral, Swift, Spatial Graph Contrastive Learning

发表于:PMLR24 推荐指数: #paper/⭐⭐⭐ 总结做了什么: 利用gcn对比学习训练mlp来提取特征嵌入,使得训练完毕使用的时候,可以更快的得到嵌入(类似于师生蒸馏的加速).其中,结合了异配图的chebnet2,以及高通低通过滤,和非对称对比学习等 看图解释:作者将全通的MLP训练得到的嵌入…

PostgreSQL入门与进阶学习,体系化的SQL知识,完成终极目标高可用与容灾,性能优化与架构设计,以及安全策略

​专栏内容&#xff1a; postgresql使用入门基础手写数据库toadb并发编程 个人主页&#xff1a;我的主页 管理社区&#xff1a;开源数据库 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 文章目录 概述基础篇初级篇进阶篇…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 7月31日,星期三

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年7月31日 星期三 农历六月廿六 1、 海关总署&#xff1a;我国关税总水平目前已经降至7.3%&#xff0c;接近发达国家平均水平。 2、 网络身份证要来了&#xff1a;两部门征求意见&#xff0c;拟为社会公众统一签发网号、网证…

HighConcurrencyCommFramework c++通讯服务器框架 :网路通迅实战

数据总在两端进行&#xff0c;一个客户端&#xff0c;一个服务器端 连接建立起来&#xff0c;数据双向流动&#xff0c;这叫双工&#xff0c;你可以发给我我也可以发给你 既然服务器端是被动的接受的&#xff0c;那么客户端必须得知道服务器的地址 我浏览器要访问的淘宝网&a…

基于Spring boot + Vue的加油站系统

项目名称&#xff1a;加油站系统 作者的B站地址&#xff1a;程序员云翼的个人空间-程序员云翼个人主页-哔哩哔哩视频 csdn地址&#xff1a;程序员云翼-CSDN博客 1.项目技术栈&#xff1a; 前后端分离的项目 后端&#xff1a;Springboot MybatisPlus 前端&#xff1a;Vue…

Jetbrains Idea插件开发教程

背景介绍 痛点&#xff1a;在idea开发过程中&#xff0c;希望按需驼峰选中文本。现在默认是一整个单词选中&#xff0c;只有在设置–>智能按键 中开启了使用"CamelHumps单词"时能够驼峰选中。但是这种情况比较粗暴&#xff0c;直接全局开启了。但是在日常开发中&…

论文《Few-Shot Object Detection with Model Calibration》的解读

《Few-Shot Object Detection with Model Calibration》论文的解读 作者&#xff1a;Qi Fan1, Chi-Keung Tang1 , and Yu-Wing Tai1,2 单位&#xff1a;1 The Hong Kong University of Science and Technology, 2 Kuaishou Technology 邮箱&#xff1a;fanqicsgmail.com, ckta…

Unity | Shader基础知识(第二十一集:应用-怪兽膨胀、顶点着色器和表面着色器合并)

目录 一、前言 二、资源介绍 三、顶点着色器和表面着色器一起使用基础 1.使用表面着色器代码 2.光照选择 3.加入顶点着色器 4.补充表面着色器 四、在顶点着色器中完成怪兽膨胀功能 1.膨胀原理解释 2.完成膨胀代码 1&#xff09;.写出需要的结构体 2&#xff09…

修改所属用户/用户组——chown

目录 &#xff08;1&#xff09;修改所属用户 &#xff08;2&#xff09;修改所属用户组 &#xff08;3&#xff09;修改所属用户和用户组 &#xff08;4&#xff09; 选项 -R 使用 chown 可以修改文件/文件夹的所属用户&#xff0c;所属用户组&#xff1b; 当然与 chmod …

7thonline第七在线出席中服协时尚科技峰会 探讨AI商品管理落地

7月25-26日&#xff0c;中国服装协会2024中国时尚科技创新峰会在杭州隆重举行&#xff0c;本次大会以“新质焕能&#xff0c;革故鼎新”为主题&#xff0c;为持续推动服装产业鼎力创新&#xff0c;以新质生产力的新特征为引领&#xff0c;布局高质量发展新赛道&#xff0c;充分…

MySQL基础练习题15-进店却未进行交易过的顾客

题目&#xff1a;有一些顾客可能光顾了购物中心但没有进行交易。来查找这些顾客的 ID &#xff0c;以及他们只光顾不交易的次数。 准备数据 分析数据 题目&#xff1a;有一些顾客可能光顾了购物中心但没有进行交易。来查找这些顾客的 ID &#xff0c;以及他们只光顾不交易的次…

c++迭代器的介绍

迭代器主要的作用就是为了可以像数组那样实现指针向后移动到下一个数据。同时迭代器统一了所有容器&#xff0c;让所有容器可以通过迭代器互通数据。 那么下面我们来看看迭代器 数组的优势 我们数组的优势就是内存连续&#xff0c;那么我们将首地址的地址进行加减就可以访问…