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

【Linux网络编程三】Udp套接字编程(简易版服务器)

【Linux网络编程三】Udp套接字编程(简易版服务器)

  • 一.创建套接字
  • 二.绑定网络信息
    • 1.构建通信类型
    • 2.填充网络信息
      • ①网络字节序的port
      • ②string类型的ip地址
    • 3.最终绑定
  • 三.读收消息
    • 1.服务器端接收消息recvfrom
    • 2.服务器端发送消息sendto
    • 3.客户端端发送消息sendto
    • 4.客户端端接收消息recvfrom
  • 四.关于绑定ip与port细节
  • 五.客户端不需要主动绑定
  • 六.客户端/服务器端代码

UDP套接字编程:
网络通信本质是进程之间通信,所以我们需要两个进程来网络通信,假设一个为服务器进程,一个为客户端进程演示。

一.创建套接字

在这里插入图片描述
socket()接口可以用来创建套接字,它总共有三个参数。

第一个参数domain,表示通信的类型,是使用网络通信还是本地通信由用户选择,当传入AF_INET/AF_INET6时表示使用网络通信。
第二个参数type,表示套接字的类型,是TCP呢还是UDP呢。如果传递SOCK_DGRAM表示是UDP,如果传递的SOCK_STREAM表示是TCP.
第三个参数protocol,表示协议,默认为0.

创建套接字成功后会返回一个文件描述符sockfd,也就是创建套接字的本质就是打开一个文件!
在这里插入图片描述

服务器端进程在创建完套接字后,该做什么呢?该套接字(文件)是属于你服务器进程的,然后呢?假设客户端也打开一个套接字(文件),这两个套接字文件都是属于同一个,也就是满足了进程间通信的前提条件:能看到一个共享资源。
而两个进程看到同一份资源后,那么该如何准确的发送给对方呢?因为可能打开这个套接字文件的进程有很多。所以接下来就是两个进程需要知道各自对方能够唯一标识自己的ip地址和端口号等网络信息。这样才能够准确的将数据从客户端进程发送给服务器进程。

 // 1.创建udp套接字,本质就是打开网络套接字文件_sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0) // 表示创建失败{lg(Fatal, "socket create error,socket: %d", _sockfd);exit(SOCKET_ERR); // 创建失败之间退出}

二.绑定网络信息

套接字创建成功后,就相当于打开了一个文件,该文件是就两个进程通信的共享资源,不过要想准确通信,还需要知道各自进程的ip地址和端口号,这样往文件里传输数据时,对端才能准确接收到,也就是这个文件需要绑定一些各自进程的网络信息才能准确的传递到对端。

进程之间网络通信需要先绑定端口号,这里创建完套接字后,就需要让该进程的端口号与套接字绑定。这样对端的进程才能找到这个进程
在这里插入图片描述
第一个参数就是创建的套接字,也就是文件对象
第二个参数就是要绑定的该进程的网络信息,包括端口号,ip地址等
第三个参数是网络信息结构体对象的大小
这个网络信息结构体对象要求传的是统一的接口,但是你实际使用什么类型的网络通信,你就定义什么类型,然后传递时强转即可。

 // 在绑定套接信息之前,需要先将对应的结构体对象填充完毕sock_addrstruct sockaddr_in local;                       // 网络通信类型bzero(&local, sizeof(local));                   // 将内容置为0local.sin_family = AF_INET;                     // 网络通信类型local.sin_port = htons(_port);                  // 网络通信中,端口号需要不断发送,所以需要符合网络字节序,主机--->网络字节序local.sin_addr.s_addr = inet_addr(_ip.c_str()); // 需要将string类型的ip转换成int类型,并且还需要满足网络字节序的要求socklen_t len = sizeof(local);// 以上只是将要绑定的信息填充完毕,套接字(网络文件)而还没有绑定套接信息

1.构建通信类型

比如如果我要网络通信,那么就需要定义一个sockaddr_in结构体对象。
在这里插入图片描述
该结构体对象里有三个需要初始化的参数:
1.sin_family:要使用的通信类型
2.sin_port:该进程的端口号
3.sin_addr:该进程的ip地址

sin_addr这个结构体对象里面只有一个参数,s_addr这个也就是真正的ip地址。

2.填充网络信息

①网络字节序的port

在给套接字绑定网络信息之前,需要将网络信息给构建好,就比如端口号,我们需要将当前进程的端口号填充到sockaddr_in这个结构体对象里。
不过端口号在网络通信中,是要不但的来回发送的,不管是客户端,还是服务器端,两个进程通信就必须知道对方的端口号。
所以端口号是需要发送到网络里的,所以在填充时,必须是网络字节序。
在这里插入图片描述
也就是主机转网络字节序

②string类型的ip地址

用户一般喜欢用string类型的ip地址类型,这样比较好显示。
但是系统里的ip是uint16_t类型的,所以我们在填充初始化时.
【要求1】首先需要将string类型的参数转换成uint16_t类型。
在这里插入图片描述

【要求2】其次ip地址也需要发送到网络里的,所以也必须是网络字节序。
在这里插入图片描述
系统里给了我们相关的接口:inet_addr(char*cp)
在这里插入图片描述

它就是可以将string类型的数据转换成uint16_t类型,并且将主机字节序转换成网络字节序。

3.最终绑定

在这里插入图片描述

  if (bind(_sockfd, (const struct sockaddr *)&local, len) < 0) // 绑定失败{lg(Fatal, "bind sockfd error,errno:%d,err string:%s", errno, strerror(errno));exit(BIND_ERR);}lg(Info, "bind sockfd success,errno:%d,err string:%s", errno, strerror(errno)); // 绑定成功

三.读收消息

1.服务器端接收消息recvfrom

一般客户端进程对服务器进程发送消息,服务器进程接收客户端发送的消息。那么服务器进程如何接收客户端发送的消息呢?
服务器进程是从套接字接收消息,也就是该进程创建的文件里接收。
在这里插入图片描述
不过服务器除了能够接收到消息,还需要知道是谁给它发送的消息,这样它才可以将消息再发送回去。
所以就需要一个sockaddr_in结构体对象,作为输出型参数,将发送端的网络信息存储下来。也就是将客户端的网络信息带出来。

所以recvfrom的功能
1.除了接收到对端发送的消息内容
2.还可以知道对端的网络消息。知道是谁发送过来的。

            struct sockaddr_in client;socklen_t len = sizeof(client);// 服务器接收到消息,它还需要知道谁给它发送的,为了后续将应答返回过去// 利用一个输出型参数,将对方的网络信息填充到里面ssize_t n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&client, &len);if (n < 0){lg(Warning, "recvfrom sockfd err,errno: %d, err string %s", errno, strerror(errno));continue;}// 读取成功,将网络文件里的消息读取到buffer里buffer[n] = 0; // 字符串形式

2.服务器端发送消息sendto

服务器一般只要用来接收其他客户端的消息,然后加工处理,再将数据发送回去,所以服务器将数据再发送回客户端,也就是往套接字里发送消息,而要发送的客户端网络信息,刚好被存储在输出型参数里。因为客户但是主动发送消息的,服务器一定是先收到客户端发送的消息,然后会将客户端的网络消息存储起来,再根据客户端网络信息发送回去。
在这里插入图片描述

 // 3.将应答发送回去
// 发送给谁呢?服务器知道吗?服务器知道!因为在接收消息时,服务器就用一个输出型参数,将客户端的网络消息保存下来了
sendto(_sockfd, echo_string.c_str(), echo_string.size(), 0, (const struct sockaddr *)&client, len);

因为服务器端在接收客户端发送的消息时,还会保存客户端的网络信息,所以如果服务器想发送消息给客户端是很容易的。

3.客户端端发送消息sendto

客户端将消息发送给服务器端,该怎么发送呢?通过套接字(文件)发送给服务器,发送时需要服务器端的网络信息,比如ip地址端口号等,这样客户端才能准确的发送给该服务器端。
在这里插入图片描述
在这里插入图片描述

//构建服务器端的网络信息std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);struct sockaddr_in server;bzero(&server, sizeof(server));server.sin_family = AF_INET;server.sin_addr.s_addr = inet_addr(serverip.c_str()); // 将string类型转换成int类型,并且是网络字节序server.sin_port = htons(serverport);socklen_t len = sizeof(server);// 1.创建套接字---本质就是打开网络文件int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){cout << "socket create err" << endl;return 1;}// 创建成功// 2.需要绑定吗?系统会给我自动绑定,首次发送的时候就会绑定char outbuffer[1024];string message;getline(cin, message);//1.发送给服务器sendto(sockfd, message.c_str(), message.size(), 0, (const struct sockaddr *)&server, len);

4.客户端端接收消息recvfrom

客户端要想接收服务器发送回来的消息,只需要读取套接字里的消息即可。利用recvfrom接口读取客户端的套接字。
不过还需要定义一个结构体对象用来保存服务器端的网络信息,虽然客户端已经知道,但是接口要求,所以必须定义。

        struct sockaddr_in temp;socklen_t l=sizeof(temp); //2.接收服务器的应答ssize_t s=recvfrom(sockfd,outbuffer,1023,0,(struct sockaddr*)&temp,&l);

四.关于绑定ip与port细节

【细节1】当服务器端绑定ip时,如果ip地址是’0.0.0.0"则表示任意ip地址绑定。
就表示不管客户端发送时目的ip是多少,只要消息发送到服务器的主机上,那么都可以接收,并将端口号往上发送。

也就是只要是发送到我这台主机上的报文,那么就会忽略到该报文的目的ip地址是多少,只看端口号。
这就表示任意ip地址绑定。相当于一种动态绑定。可以接收到所有发送到我这台主机上的报文。并往上传递。
在这里插入图片描述
还要注意在云服务器上,公用ip是不能随意绑定的,无法直接绑定,不管是TCP还是UDP。除非是127.0.0.1这个ip地址是专门用来检测服务器和客户端的。其他的不要瞎绑定。但是在虚拟机上可以。
【细节2】端口号不是随意绑定的,有些是已经被固定使用的,【0,1023】是属于系统内定的端口号,一般要有固定的应用层协议使用。
所以我们最好使用1023后面的。

【总结】
如果服务器端的ip地址默认是0的话,那么我们只需要知道服务器端的端口号即可。在这里插入图片描述

五.客户端不需要主动绑定

在这里插入图片描述
所以客户端是不需要显示的绑定相关的端口号和ip地址的。操作系统会帮它自动绑定。
本质原因是用户不关心客户端的端口号和ip地址等网络信息,所以不需要显示绑定。
关键是要唯一。由操作系统随机选择。

但是服务器端必须主动绑定端口号!为什么呢?
因为用户关心服务器的端口号,必须知道服务器端的端口号。不然无法找到服务器端。
在这里插入图片描述

六.客户端/服务器端代码

【客户端】

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>using namespace std;#include <iostream>
#include <strings.h>
#include <sys/types.h>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
// 客户端
void Usage(std::string proc)
{std::cout << "\n\r./Usage: " << proc << " serverip serverport\n"<< endl;
}
// 启动客户端时要求是: ./Client 服务器ip 服务器port
int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(0);}std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);struct sockaddr_in server;bzero(&server, sizeof(server));server.sin_family = AF_INET;server.sin_addr.s_addr = inet_addr(serverip.c_str()); // 将string类型转换成int类型,并且是网络字节序server.sin_port = htons(serverport);socklen_t len = sizeof(server);// 1.创建套接字---本质就是打开网络文件int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){cout << "socket create err" << endl;return 1;}// 创建成功// 2.需要绑定吗?系统会给我自动绑定,首次发送的时候就会绑定// 3.往服务器的套接字里发送消息--需要知道服务器的ip和端口号,目的ip和目的port,将ip和port填入结构体对象里char outbuffer[1024];string message;while (true){cout<<"Please enter@ ";getline(cin, message);//1.发送给服务器sendto(sockfd, message.c_str(), message.size(), 0, (const struct sockaddr *)&server, len);struct sockaddr_in temp;socklen_t l=sizeof(temp); //2.接收服务器的应答ssize_t s=recvfrom(sockfd,outbuffer,1023,0,(struct sockaddr*)&temp,&l);if(s>0){//接收成功outbuffer[s]=0;cout<<outbuffer<<endl;}}close(sockfd);return 0;
}

【服务器端】

@ -0,0 +1,103 @@
#pragma once#include "Log.hpp"
#include <iostream>
#include <string>
#include <strings.h>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
std::string defaultip = "0.0.0.0";
uint16_t defaultport = 8080;
Log lg; // 日志,默认往显示屏打印
typedef std::function<std::string(const std::string&)> func_t;//相当于定义了一个函数指针
//返回值是string类型,函数参数也是string类型,利用函数回调的方法,将服务器端对数据的处理操作进行分离,由上层传递的函数来决定如何处理
enum
{SOCKET_ERR = 1,BIND_ERR
};
class Udpserver
{
public:Udpserver(const uint16_t &port = defaultport, std::string &ip = defaultip) : _sockfd(0), _port(port), _ip(ip){}void Init(){// 1.创建udp套接字,本质就是打开网络套接字文件_sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0) // 表示创建失败{lg(Fatal, "socket create error,socket: %d", _sockfd);exit(SOCKET_ERR); // 创建失败之间退出}// 创建成功lg(Info, "socket create success,socket: %d", _sockfd);// 2.绑定服务器的套接信息,比如ip和端口号// 在绑定套接信息之前,需要先将对应的结构体对象填充完毕sock_addrstruct sockaddr_in local;                       // 网络通信类型bzero(&local, sizeof(local));                   // 将内容置为0local.sin_family = AF_INET;                     // 网络通信类型local.sin_port = htons(_port);                  // 网络通信中,端口号需要不断发送,所以需要符合网络字节序,主机--->网络字节序local.sin_addr.s_addr = inet_addr(_ip.c_str()); // 需要将string类型的ip转换成int类型,并且还需要满足网络字节序的要求socklen_t len = sizeof(local);// 以上只是将要绑定的信息填充完毕,套接字(网络文件)而还没有绑定套接信息if (bind(_sockfd, (const struct sockaddr *)&local, len) < 0) // 绑定失败{lg(Fatal, "bind sockfd error,errno:%d,err string:%s", errno, strerror(errno));exit(BIND_ERR);}lg(Info, "bind sockfd success,errno:%d,err string:%s", errno, strerror(errno)); // 绑定成功}void Run(func_t func) // 服务器是一旦启动不会退出,服务器接收消息,并发送答应{// 1.接收信息char buffer[SIZE];while (true){struct sockaddr_in client;socklen_t len = sizeof(client);// 服务器接收到消息,它还需要知道谁给它发送的,为了后续将应答返回过去// 利用一个输出型参数,将对方的网络信息填充到里面ssize_t n = recvfrom(_sockfd, buffer, sizeof(buffer)-1, 0, (struct sockaddr *)&client, &len);if (n < 0){lg(Warning, "recvfrom sockfd err,errno: %d, err string %s", errno, strerror(errno));continue;}// 读取成功,将网络文件里的消息读取到buffer里buffer[n] = 0; // 字符串形式// 2.加工处理// std::string info = buffer;// std::string echo_string  = "server echo# " + info;std::string info=buffer;std::string echo_string=func(info);//将接收的信息由外层函数进行处理// 3.将应答发送回去// 发送给谁呢?服务器知道吗?服务器知道!因为在接收消息时,服务器就用一个输出型参数,将客户端的网络消息保存下来了sendto(_sockfd, echo_string.c_str(), echo_string.size(), 0, (const struct sockaddr *)&client, len);}}~Udpserver(){if (_sockfd > 0)close(_sockfd);}private:int _sockfd;     // 套接字文件描述符std::string _ip; // 我们习惯用string类型的ip地址uint16_t _port;  // 服务器进程的端口号
};

#include "Udpserver.hpp"
#include <memory>
#include <cstdio>
#include <stdlib.h>
// "120.78.126.148" 点分十进制字符串风格的IP地址
std::string handler(const std::string &info)
{ std::string res="get a message: ";res+=info;std::cout<<res<<std::endl;return res;//最后将处理的数据返回回去
}#include "Udpserver.hpp"
#include <memory>
#include <cstdio>void Usage(std::string proc)
{std::cout<<"\n\rUsage: "<<proc<<" port[1024+]\n"<<std::endl;
}
//服务器进程,启动时,按照./Udpserver+port的形式传递
int main(int args,char* argv[])
{if(args!=2){Usage(argv[0]);exit(0);}uint16_t port=std::stoi(argv[1]);std::unique_ptr<Udpserver> svr(new Udpserver(port));//首先创建一个服务器对象指针//智能指针,用一个UdpServer指针来管理类对象svr->Init();//初始化服务器svr->Run(handler);//启动服务器return 0;
} 

在这里插入图片描述

相关文章:

【Linux网络编程三】Udp套接字编程(简易版服务器)

【Linux网络编程三】Udp套接字编程(简易版服务器&#xff09; 一.创建套接字二.绑定网络信息1.构建通信类型2.填充网络信息①网络字节序的port②string类型的ip地址 3.最终绑定 三.读收消息1.服务器端接收消息recvfrom2.服务器端发送消息sendto3.客户端端发送消息sendto4.客户端…...

【Rust】字符串,看这篇就够了

这节课我们把字符串单独拿出来讲&#xff0c;是因为字符串太常见了&#xff0c;甚至有些应用的主要工作就是处理字符串。比如 Web 开发、解析器等。而 Rust 里的字符串内容相比于其他语言来说还要多一些。是否熟练掌握 Rust 的字符串的使用&#xff0c;对 Rust 代码开发效率有很…...

单片机和 ARM 的区别

单片机和 ARM 在功能和使用上有一些区别&#xff0c;因此哪个更好用取决于具体的需求和场景。 单片机是一种集成了微处理器、存储器和外设接口的集成电路芯片&#xff0c;通常具有体积小、功耗低、可靠性高、成本低等特点。单片机广 泛应用于各种领域&#xff0c;如智能仪表、工…...

JavaScript从入门到精通系列第三十一篇:详解JavaScript中的字符串和正则表达式相关的方法

文章目录 知识回顾 1&#xff1a;概念回顾 2&#xff1a;正则表达式字面量 一&#xff1a;字符串中正则表达式方法 1&#xff1a;split 2&#xff1a;search 3&#xff1a;match 4&#xff1a;replace 知识回顾 1&#xff1a;概念回顾 正则表达式用于定义一些字符串的…...

23、数据结构/查找相关练习20240205

一、请编程实现哈希表的创建存储数组{12,24,234,234,23,234,23},输入key查找的值&#xff0c;实现查找功能。 代码&#xff1a; #include<stdlib.h> #include<string.h> #include<stdio.h> #include<math.h> typedef struct Node {int data;struct n…...

【VSTO开发-WPS】下调试

重点2步&#xff1a; 1、注册表添加 Windows Registry Editor Version 5.00[HKEY_CURRENT_USER\Software\kingsoft\Office\WPP\AddinsWL] "项目名称"""2、visual studio 运行后&#xff0c;要选中附加到调试&#xff0c;并指定启动项目。 如PPT输入WPP搜…...

git 的基本概念

当使用Git时&#xff0c;一些基本概念包括&#xff1a; 1. **仓库&#xff08;Repository&#xff09;&#xff1a;** 存储项目文件和版本历史的地方。可以是本地仓库&#xff08;在你的计算机上&#xff09;或远程仓库&#xff08;在服务器上&#xff09;。 2. **提交&#…...

《统计学习方法:李航》笔记 从原理到实现(基于python)-- 第6章 逻辑斯谛回归与最大熵模型(1)6.1 逻辑斯谛回归模型

文章目录 第6章 逻辑斯谛回归与最大熵模型6.1 逻辑斯谛回归模型6.1.1 逻辑斯谛分布6.1.2 二项逻辑斯谛回归模型6.1.3 模型参数估计6.1.4 多项逻辑斯谛回归 《统计学习方法&#xff1a;李航》笔记 从原理到实现&#xff08;基于python&#xff09;-- 第3章 k邻近邻法 《统计学习…...

Go 中如何检查文件是否存在?可能产生竞态条件?

嗨&#xff0c;大家好&#xff01;本文是系列文章 Go 技巧第十三篇&#xff0c;系列文章查看&#xff1a;Go 语言技巧。 Go 中如何检查文件是否存在呢&#xff1f; 如果你用的是 Python&#xff0c;可通过标准库中 os.path.exists 函数实现。遗憾的是&#xff0c;Go 标准库没有…...

红日靶场1搭建渗透

环境搭建 下载好镜像文件并解压&#xff0c;启动vmware 这里我用自己的win7 sp1虚拟机作为攻击机&#xff0c;设置为双网卡NAT&#xff0c;vm2 其中用ipconfig查看攻击机ip地址 设置win7 x64为双网卡&#xff0c;vm1&#xff0c;vm2 设置win08单网卡vm1&#xff0c;win2k3为单…...

ChatGPT之搭建API代理服务

简介 一行Docker命令部署的 OpenAI/GPT API代理&#xff0c;支持SSE流式返回、腾讯云函数 。 项目地址&#xff1a;https://github.com/easychen/openai-api-proxy 这个项目可以自行搭建 OpenAI API 代理服务器工具&#xff0c;该项目是代理的服务器端&#xff0c;不是客户端。…...

Kotlin手记(一):基础大杂烩

Kotlin简介 2011年7月&#xff0c;JetBrains推出Kotlin项目&#xff0c;这是一个面向JVM的新语言 2012年2月&#xff0c;JetBrains以Apache 2许可证开源此项目。 2016年2月15日&#xff0c;Kotlin v1.0发布&#xff0c;这被认为是第一个官方稳定版本。 在Google I/O 2017中&am…...

redis源码之:集群创建与节点通信(2)

在上一篇redis源码之&#xff1a;集群创建与节点通信&#xff08;1&#xff09;我们可知&#xff0c;在集群中&#xff0c;cluster节点之间&#xff0c;通过meet将对方加入到本方的cluster->nodes列表中&#xff0c;并在后续过程中&#xff0c;不断通过clusterSendPing发送p…...

2024.2.5 寒假训练记录(19)

文章目录 牛客 寒假集训2A Tokitsukaze and Bracelet牛客 寒假集训2B Tokitsukaze and Cats牛客 寒假集训2D Tokitsukaze and Slash Draw牛客 寒假集训2E Tokitsukaze and Eliminate (easy)牛客 寒假集训2F Tokitsukaze and Eliminate (hard)牛客 寒假集训2I Tokitsukaze and S…...

游戏服务器租赁多少钱一台?26元,服不服?

游戏服务器租用多少钱一年&#xff1f;1个月游戏服务器费用多少&#xff1f;阿里云游戏服务器26元1个月、腾讯云游戏服务器32元&#xff0c;游戏服务器配置从4核16G、4核32G、8核32G、16核64G等配置可选&#xff0c;可以选择轻量应用服务器和云服务器&#xff0c;阿腾云atengyu…...

wpf 引入本项目的图片以及引入其他项目的图像资源区别及使用方法

在WPF项目中引入本项目的图片和引入其他项目的图像资源&#xff0c;两者的主要区别在于资源的位置以及如何通过URI引用它们。以下是详细说明及使用方法&#xff1a; ​ 一、引入本项目的图片资源&#xff1a; 将图片文件&#xff08;如PNG, JPG等&#xff09;放入你的WPF项目…...

jsp页面,让alert弹出信息换行显示

第一种方式&#xff1a;后端拼接上换行符前端显示 1&#xff0c;java后端将信息封装成字符串时&#xff0c;在需要换行的地方拼接上一个换行符&#xff0c; 显示在HTML中的换行&#xff0c;通常需要用<br>标签替代\n&#xff0c;如下&#xff1a; String javaString &…...

【IC设计】Windows下基于IDEA的Chisel环境安装教程(图文并茂)

Chisel环境安装教程 第一步 安装jdk&#xff0c;配置环境变量第二步 安装sbt&#xff0c;不用配置环境变量第三步 安装idea社区版第四步 离线安装scala的idea插件第五步 配置sbt换源1.切换目录2.创建repositories文件3.配置sbtconfig.txt文件 第六步 使用chisel-tutorial工程运…...

IF=82.9!高分文献解读|吉西他滨联合顺铂化疗激活肿瘤免疫新机制

鼻咽癌&#xff08;nasopharyngeal carcinoma, NPC&#xff09;是一种发生于鼻咽部上皮细胞的恶性肿瘤&#xff0c;且高发于中国。吉西他滨联合顺铂&#xff08;GP&#xff09;化疗作为鼻咽癌的一种全球标准治疗方案&#xff0c;然而治疗的具体机制目前尚不清楚。中山大学肿瘤防…...

【QT+QGIS跨平台编译】之二十八:【Protobuf+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、Protobuf介绍二、文件下载三、文件分析四、pro文件4.1 libprotobuf4.2 libprotobuf-lite4.3 libprotoc4.4 protocApp五、编译实践一、Protobuf介绍 Protocol Buffers(简称 Protobuf)是由 Google 开发的一种数据序列化协议,就像 XML 或 JSON 一样,但是它更小、…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

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

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

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...