简单的 UDP 网络程序
文章目录:
- 简单的UDP网络程序
- 服务端创建套接字
- 服务端绑定
- 启动服务器
- udp客户端
- 本地测试
- INADDR_ANY
- 地址转换函数
- 关于 inet_ntoa
简单的UDP网络程序
服务端创建套接字
我们将服务端封装为一个类,当定义一个服务器对象之后,需要立即进行初始化服务器,在 UDP 网络程序中,初始服务器的第一个步骤就是创建套接字。我们使用 socket 函数创建套接字。
socket 函数的定义如下所示:
int socket(int domain, int type, int protocol);
参数说明:
domain
:整数,指定通信域(Communication Domain)。在同一主机上的进程之间进行通信时,我们使用 POSIX 标准定义的 AF_LOCAL。在不同的主机通过 IPv4 连接的进程之间通信时,我们使用 AF_INET,对于通过 IPv6 连接的进程之间进行通信时,我们使用 AF_INET6。type
:通信类型(Communication Type)。SOCK_STREAM:TCP(可靠的、面向连接的);SOCK_DGRAM:UDP(不可靠的、无连接的)。protocol
:互联网协议的协议值,通常为0。这与数据包的 IP 头中的协议字段中显示的数字相同。
返回值:套接字创建成功返回一个文件描述符,否则返回-1,同时错误码被设置。
在初始化服务器创建套接字时,需要调用 socket 函数创建套接字,我们需要填入的协议家族是 AF_INET(PF_INET),因为我们需要进行的是网络通信。服务器类型填入 SOCK_DGRAM ,因为编写的 UDP 服务器是面向数据报的。第三个参数设置为0,表示使用默认的传输协议。
下面是使用这些参数创建套接字的示例:
#include<iostream>
#include<sys/socket.h>class UdpServer
{
public:void init(){// 创建套接字sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd_ < 0){std::cerr << "Failed to create socket." << std::endl;exit(1);}std::cout << "socket create success, sockfd: " << sockfd_ << std::endl;// ......}
private:int sockfd_; // 文件描述符
};
我们对其进行一个测试,查看套接字的创建是否成功。
int main()
{UdpServer *svr=new UdpServer();svr->init();return 0;
}
运行测试结果:
服务端绑定
在套接字创建成功之后,需要将其与网络相关联,以便进行网络通信。对于一个 UDP 服务器,绑定操作是必要的。通过绑定,将套接字与指定的IP地址和端口号关联起来,以便监听和处理该地址上的网络数据。
使用 bind 函数将套接字与特定的IP地址和端口号进行绑定,bind 函数的定义如下:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数说明:
sockfd
:需要绑定的套接字描述符。addr
:指向要绑定的地址结构的指针,需要将其转化为 struct sockaddr 类型。addrlen
:地址结构长度。
返回值:
- 绑定成功返回0。失败则返回-1,且错误码被设置。
bind 函数的主要作用就是将套接字与指定的地址进行关联,以便在该地址上进行监听和处理网络数据。调用 bind 之前,需要确保套接字已经创建成功。
在绑定套接字之前,需要定义一个 struct sockaddr_in 结构,并将网络属性信息填充到该结构体中。由于 struct sockaddr_in 结构体中的一些字段是可选的,建议在填充网络信息之前先将结构体变量进行清空,然后填充协议家族、端口号、IP地址等信息。
下列示例展示了如何使用 bind 函数将套接字绑定到指定的IP地址和端口号:
class UdpServer
{
public:UdpServer(int port = 8080, std::string ip = ""): port_((uint16_t)port), ip_(ip), sockfd_(-1){}~UdpServer() {}void init(){// 1.创建套接字sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd_ < 0){std::cerr << "Failed to create socket." << std::endl;exit(1);}std::cout << "socket create success, sockfd: " << sockfd_ << std::endl;// 2.绑定网络信息,指明IP+port// 2.1 先填充基本信息到 struct sockaddr_instruct sockaddr_in local; // lock在用户栈上开辟的空间 -> 临时变量 -> 写入内核中bzero(&local, sizeof(local)); // bzerolocal.sin_family = AF_INET; // 填充协议家族,域local.sin_port = htons(port_); // 填充服务器对应的端口信息,一定会发给对方,_port一定会到网络中// local.sin_addr // 服务器都必须具有IP地址("xx.yy.zz.aaa"字符串风格点分十进制) -> 4字节IP -> uint32_t iplocal.sin_addr.s_addr = ip_.empty() ? htonl(INADDR_ANY) : inet_addr(ip_.c_str());// 2.2 绑定网络信息if (bind(sockfd_, (struct sockaddr *)&local, sizeof(local)) == -1){std::cerr << "Failed to bind socket." << std::endl;exit(2);}std::cout << "Socket bound successfully." << std::endl;}private:uint16_t port_; // 服务器必须得有端口号信息std::string ip_; // 服务器必须得有IP地址int sockfd_; // 文件描述符
};
启动服务器
UDP 服务器的初始化在上面已经完成。服务器初始化完成之后,就可以启动服务器并提供服务了。服务器通常是以循环的方式运行的,以便持续接收和处理客户端请求。UDP 服务器在接收到客户端发送的数据后,可以直接读取这些数据,而无需建立连接。
recvfrom函数:
recvfrom 函数是在网络编程中使用的一个系统调用函数,用于从一个指定的套接字接收数据,并将数据存储到指定的缓冲区中。
recvfrom 函数的定义如下:
#include <sys/types.h>
#include <sys/socket.h>ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
- sockfd:套接字描述符,表示从该套接字描述符索引的文件中读取数据。
- buf:指向接收数据的缓冲区。
- len:期望读取数据的字节数。
- flags:可选的标志参数,用于控制接收操作的行为。常用的标志有:0、MSG_DONTWAIT。
- src_addr:指向用于存储发送方地址信息的 struct sockaddr 结构体的指针,包括协议家族、IP地址、端口号等。
- addrlen:src_addr 结构体的长度,及其可用空间大小,这是一个输出型参数。
当使用 recvfrom 函数接收 UDP 数据时,除了获取数据内容外,还可以获取发送方的网络属性信息,包括IP地址和端口号。调用 recvfrom 函数之前,需要将 addrlen 参数设置为接收方地址结构体的大小,以确保函数可以正确填充发送方的地址信息。
接下来使用下列函数启动服务器:
当使用 recvfrom 函数读取客户端数据后,可以将读取到的数据视为字符串,并将最后一个位置设置为 ‘\0’ ,以便于进行输出。此时,我们也获取到了客户端的IP地址和端口号。recvfrom 函数调用成功之后返回的端口号是网络序列(以大端字节序表示),我们需要调用 ntohs 函数将其转换为主机序列(与本地字节序相匹配)。同样的,获取的IP地址也需要用 inet_ntoa 函数进行转化。
class UdpServer
{
public:void start(){// 服务器设计的时候都是死循环char inbuffer[1024]; // 储存读取到的数据char outbuffer[1024]; // 储存发送的数据while (true){struct sockaddr_in peer; // 输出型参数socklen_t len = sizeof(peer); // 输入型参数ssize_t s = recvfrom(sockfd_, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr *)&peer, &len);if (s > 0)inbuffer[s] = 0; // 将其当作字符串else if (s == -1){std::cerr << "recvfrom:" << strerror(errno) << ":" << sockfd_ << endl;continue; // 调用失败,继续进行读取,服务器不能因为一个客户端连接失败就退出}// 读取成功,除了读取到对方的数据,还要读取到对方的网络地址[ip,port]std::string peerIp = inet_ntoa(peer.sin_addr);uint32_t peerPort = ntohs(peer.sin_port);}}private:uint16_t port_; // 服务器必须得有端口号信息std::string ip_; // 服务器必须得有IP地址int sockfd_; // 文件描述符
};
在构建服务器时,我们可以引入命令行参数用于指定服务器的IP地址和端口号。使用云服务器,实际上不需要传入IP地址,直接运行程序时指定端口即可,这里可以将IP地址设置为(127.0.0.1),它代表本地主机或本地环回地址,相当于 localhost 。
以下为一个示例代码,演示如何通过命令行参数传递端口号,并将IP地址设置为本地环回地址:
static void Usage(const std::string proc)
{cout << "Usage:\n\t" << proc << " port [ip]" << endl;
}// ./udpServer port [ip]
int main(int argc,char *argv[])
{if(argc!=2&&argc!=3){Usage(argv[0]);return 1;}std::string ip="127.0.0.1";uint16_t port=atoi(argv[1]);UdpServer svr(port,ip);svr.init();svr.start();
}
如下所示,运行程序并加上端口号就可以创建 udp 服务器成功了:
使用 netstat
命令来查看当前网络的状态,下图标出的就是当前运行的 udpServer 程序:
netstat
是一个用于显示网络连接、路由表和网络接口等相关信息的命令。以下是 netstat
常用的选项:
-a
(all):显示所有的sockets(包括监听和非监听的)。-t
(tcp):显示 TCP 协议相关的连接信息。-u
(udp):显示 UDP 协议相关的连接信息。-n
(numeric):以数字形式显示IP地址和端口号,不进行主机名和服务名的解析。-p
(program):显示与每个连接关联的进程/程序的 PID 和名称。-l
(listening):显示每个处于监听状态的 sockets。
注意:不同操作系统上的 netstat 命令可能会不同,包括选项的名称和支持的功能。因此,在使用 netstat 命令时可以通过 netstat --help
来查看系统文档使用说明。
udp客户端
udp客户端的实现步骤如下所示,用于与服务器进行 UDP 通信:
参数检查
:通过检查命令行参数,来确保命令行输入的参数个数是否正确,这是为了确保程序能够正确获取服务器的IP地址和端口号,避免后续出现错误。获取服务端的IP地址和端口号
:根据命令行参数获取服务器的IP地址和端口号,并将它们存储在变量 server_ip 和 server_port 中。这样客户端就获取到了需要连接服务器的地址信息。创建 UDP 套接字
:使用 socket 函数创建一个 UDP 套接字,即创建一个用于网络通信的套接字。AF_INET 参数表示使用 IPv4 地址,SOCK_DGRAM 参数表示使用数据报(UDP) 套接字类型。创建套接字成功之后,会返回一个文件描述符,用于后续该套接字的操作。设置服务器地址信息
:UDP 通信中,需要指定连接的服务器地址信息。这里通过填充 server 结构体来实现。bzero 函数将 server 结构体清零。sin_family 表示地址族为 IPv4 ,sin_port 表示服务器的端口号,sin_addr.s_addr 表示服务器的IP地址。
// ./udpServer server_ip server_port
// 客户端要连接服务端,需要知道server对应的IP和port
class UdpClient
{
public:UdpClient(std::string ip = "", uint16_t port = 8080): ip_(ip), port_(port), sockfd_(-1){}void init(){// 创建套接字sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd_ < 0){std::cerr << "socket create error" << std::endl;exit(1);}}void start(){// 填写服务器对应信息struct sockaddr_in peer;bzero(&peer, sizeof peer);peer.sin_family = AF_INET;peer.sin_port = htons(port_);peer.sin_addr.s_addr = inet_addr(ip_.c_str());std::string buffer;// 启动客户端while (true){std::cout << "Please Enter# ";getline(cin, buffer);// 发送消息给serversendto(sockfd_, buffer.c_str(), buffer.size(), 0, (const struct sockaddr *)&peer, sizeof(peer));}}~UdpClient(){if (sockfd_ >= 0)close(sockfd_);}private:std::string ip_;uint16_t port_;int sockfd_;
};static void Usage(const std::string name)
{cout << "Usage:\n\t" << name << " server_ip server_port" << endl;
}int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(2);}// 根据命令行,设置需要访问的服务器IPstd::string server_ip = argv[1];uint16_t server_port = atoi(argv[2]);UdpClient client(server_ip, server_port);client.init();client.start();return 0;
}
sendto函数
sendto 函数用于在 UDP 通信中发送数据,它的函数定义如下:
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
参数说明:
-
sockfd:使用 socket 函数创建的套接字描述符。
-
buf:指向要发送的数据的缓冲区的指针。数据可以是任意类型的指针,通常是一个 char 数组或字符串。
-
len:要发送的数据的长度,单位是字节。
-
flags:指定发送操作的可选标志。一般使用0或与 MSG_DONTROUTE 等特殊标志进行按位或运算。有以下常用标志:
MSG_DONTROUTE
:不使用路由表发送数据,直接发送到目的地址。
MSG_OOB
:发送外带数据。
MSG_NOSIGNAL
:在发送数据时忽略 SIGPIPE 信号,避免导致进程终止。 -
dest_addr:对端网络相关的属性信息。在 UDP 通信中,该参数指向 sockaddr 结构体的指针,其中包含了目标服务器的IP地址和端口号。
-
addrlen:传入 dest_addr 结构体的长度,通常是 sizeof(struct sockaddr_in)。
本地测试
udp 的服务端和客户端的代码都已经编写完成。因此,我们可以先在本地进行测试,使用本地环回地址(127.0.0.1)作为服务器的IP地址,客户端可以连接到该地址来与服务器进行通信。同时,我们需要确保服务器绑定的端口号与客户端连接时指定的端口号一致。
当客户端和服务端成功建立连接并进行通信时,可以通过使用 netstat
命令来看网络信息来确认连接的建立。
INADDR_ANY
INADDR_ANY 是一个IP地址,当我们不想将套接字绑定到任何特定的IP时使用。在实现通信时,我们需要将套接字绑定到IP地址。当我们不知道自己及其的IP地址或者其它情况时,可以使用特殊的IP地址 INADDR_ANY。它允许我们的服务器接收任何接口作为目标的数据包。
在进行网络测试时,你需要确保服务器能够通过公网IP地址进行访问。然而,直接将服务器绑定到公网IP可能会导致绑定失败的问题。
在云服务器中,你所获得的公网IP地址并不一定是真正的公网IP,而是有云服务器厂商提供的内部IP地址,这些内部IP地址无法直接在服务器代码中进行绑定。
为了让服务器能够通过公网IP进行访问,可以使用一个特殊的绑定值,即 INADDR_ANY
。这个值是系统提供的宏,对应的数值为0。通过将服务器绑定到 INADDR_ANY
,就可以让服务器接收来自任意IP地址的连接请求。
若想要我们写的服务端能够被外部网络进行访问,我们可以这样做:
- 在服务器代码中,将与IP地址相关的代码去掉。这样可以使服务器动态绑定到可用的IP地址。
- 填充 struct sockaddr_in 结构体时,将IP地址设置为 INADDR_ANY 。这样服务器就可以接收到来自任意IP地址的连接请求了。
struct sockaddr_in peer;
bzero(&peer, sizeof peer);
peer.sin_family = AF_INET;
peer.sin_port = htons(port_);
peer.sin_addr.s_addr = INADDR_ANY;
注意:INADDR_ANY
的值是0,它不需要进行网络字节序的转化。因此,在设置时无需进行大小端的处理。
编译并运行修改后的代码时,再次使用 netstat
命令查看网络连接情况时,该服务器的IP地址变成了 0.0.0.0
,意味着该服务器可以接收任意主机发起的连接请求:
地址转换函数
这里主要介绍的是 IPv4 的 socket 网络编程。sockaddr_in 中的成员 struct in_addr sin_addr 表示32位的IP地址。但是我们通常使用点分十进制的字符串表示IP地址,以下函数可以在字符串表示和 in_addr 表示之间进行转换:
字符串转 in_addr 的函数:
#include <arpa/inet.h>// 将字符串cp表示的IP地址转换为in_addr结构体,并将结果存储在inp中
int inet_aton(const char *cp, struct in_addr *inp);// 将字符串cp表示的IP地址转换为in_addr_t类型的值
in_addr_t inet_addr(const char *cp);// 将字符串从src表示的IP地址转换为指定地址族af的二进制表示,并将转换后的结果存储在dst中
int inet_pton(int af, const char *src, void *dst);
in_addr转字符串的函数:
// 将in_addr结构体中的IP地址转换为字符串形式
char *inet_ntoa(struct in_addr in);// 将指定地址族af的二进制表示src转化为字符串形式,并将结果存储在dst中
const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);
其中 inet_pton 和 inet_ntop 不仅可以转换 IPv4 的 in_addr ,还可以转换 IPv6 的 in6_addr 因此函数接口是 void *addrptr 。
关于 inet_ntoa
inet_ntoa 这个函数的返回值类型是 char*,很显然这个函数在自己内部申请了一块内存来报错IP结果,那么是否需要调用者手动释放呢?
man 手册上说,inet_ntoa 函数,是把这个结果放在了静态存储区。这时不需要我们进行手动释放。那么,若多次调用该函数,会有什么样的效果呢?
请看代码:
#include <iostream>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;int main()
{struct sockaddr_in addr1;struct sockaddr_in addr2;addr1.sin_addr.s_addr = 0;addr2.sin_addr.s_addr = 0xffffffff;char *ptr1 = inet_ntoa(addr1.sin_addr);char *ptr2 = inet_ntoa(addr2.sin_addr);cout << "ptr1:" << ptr1 << " ptr2:" << ptr2 << endl;return 0;
}
运行结果如下所示:
由于 inet_ntoa 函数使用了静态缓冲区,每次调用该函数时,返回的指针都会指向同一个缓冲区。这意味着如果在多个地方同时使用了 inet_ntoa 返回值,并且后续的调用覆盖了之前的结果,那么之前获取的字符串指针将变为无效。
思考:如果有多个线程调用 inet_ntoa,是否会出现异常情况呢?
- 在 APUE 中,明确提出了 inet_ntoa 不是线程安全的函数。因为它使用了一个全局共享的缓冲区来保存转化后的字符串。所以多线程环境下,该函数可能会导致竞争条件,从而出错。
- 但是在 centos7 上测试,并没有出现问题,这可能是在内部加了互斥锁来保证线程安全性。
- 在多线程环境下,推荐使用 inet_ntop 函数,它是线程安全的。inet_ntop 函数要求调用者提供一个缓冲区来存储转换后的字符串,避免了静态缓冲区的共享和竞争条件,可以规避线程安全的问题。
多线程调用 inet_ntoa 代码示例如下:
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>void *Func1(void *p)
{struct sockaddr_in *addr = (struct sockaddr_in *)p;while (1){char *ptr = inet_ntoa(addr->sin_addr);printf("addr1: %s\n", ptr);}return NULL;
}
void *Func2(void *p)
{struct sockaddr_in *addr = (struct sockaddr_in *)p;while (1){char *ptr = inet_ntoa(addr->sin_addr);printf("addr2: %s\n", ptr);}return NULL;
}int main()
{pthread_t tid1 = 0;struct sockaddr_in addr1;struct sockaddr_in addr2;addr1.sin_addr.s_addr = 0;addr2.sin_addr.s_addr = 0xffffffff;pthread_create(&tid1, NULL, Func1, &addr1);pthread_t tid2 = 0;pthread_create(&tid2, NULL, Func2, &addr2);pthread_join(tid1, NULL);pthread_join(tid2, NULL);return 0;
}
在该程序测试中并没有出现问题,但这并不意味着 inet_ntoa 函数在多线程环境中是安全的。为了确保线程安全,仍然建议使用线程安全的函数 inet_ntop 来替代 inet_ntoa 。
相关文章:

简单的 UDP 网络程序
文章目录: 简单的UDP网络程序服务端创建套接字服务端绑定启动服务器udp客户端本地测试INADDR_ANY 地址转换函数关于 inet_ntoa 简单的UDP网络程序 服务端创建套接字 我们将服务端封装为一个类,当定义一个服务器对象之后,需要立即进行初始化…...
人工智能-深度学习之文本预处理
文本预处理 对于序列数据处理问题, 这样的数据存在许多种形式,文本是最常见例子之一。 例如,一篇文章可以被简单地看作一串单词序列,甚至是一串字符序列。 本节中,我们将解析文本的常见预处理步骤。 这些步骤通常包括…...

【Java 进阶篇】插上翅膀:JQuery 插件机制详解
在前端开发中,JQuery 作为一个广泛应用的 JavaScript 库,为开发者提供了丰富的工具和方法,简化了 DOM 操作、事件处理等繁琐的任务。而在这个庞大的生态系统中,插件机制是 JQuery 的一项重要特性,使得开发者能够轻松地…...
手动编译GDB
手动编译GDB 起因在于使用Clang-14编译C文件并生成调试信息,使用gdb调试时报DWARF相关错误。经检查原因在于虚拟机为Ubuntu 20.04,使用apt下载时官方提供gdb版本为9.2,不支持DWARF5,而Clang-14生成的调试信息是DWARF5版本的。为解决该问题,手…...

竞赛选题 深度学习花卉识别 - python 机器视觉 opencv
文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 &a…...
替换SlowFast中Detectron2为Yolov8
一 需求 FaceBookReserch中SlowFast源码中检测框是用Detectron2进行目标检测,本文想实现用yolov8替换detectron2二 实施方案 首先,yolov8 支持有自定义库ultralytics(仅支持yolov8),安装对应库 pip install ultraly…...
轻量化网络--MobileNet V1
文章目录 depth-wise separable convolutions普通卷积depthwise conconvolutionspointwise convolutions网络结构进一步分析网络训练方式两个重要的超参数Width Multiplier: Thinner ModelsResolution Multiplier: Reduced Representation实验结果消融实验细粒度,高分辨率识别…...

gittee启动器
前言 很多小伙伴反馈不是使用gitee,不会寻找好的项目,在拿到一个项目不知道从哪里入手。 鼠鼠我呀就是宠粉,中嘞,老乡。整!!! git的基本指令 在使用gitee的时候呢,我们只需要记住…...
Spark数据倾斜_产生原因及定位处理办法_生产环境
在最近的项目中,历史和实时数据进行关联平滑时出现了数据倾斜,产生了笛卡尔积,具体现象如下:运行内存175GB,核数64,运行代码时,查看SparkUI界面的active jobs ,数据输入是1G…...

2023OceanBase年度发布会后,有感
很荣幸收到了OceanBase邀请,于本周四(11月16日)参加了OceanBase年度发布会并参加了DBA老友会,按照理论应该我昨天(星期五)就回到成都了,最迟今天白天就该把文章写出来了,奈何媳妇儿买…...
ubuntu18.04中代码迁移到20.04报错
一、 PCL库,Eigen库报错,如: /usr/include/pcl-1.10/pcl/point_types.h:903:29: error: ‘enable_if_t’ in namespace ‘std’ does not name a template type; did you mean ‘enable_if’?/usr/include/pcl-1.10/pcl/point_types.h:698:…...
QQ五毛项目记
问题与挑战:某公司为了实现某马总造福全人类,红旗插遍全球的宏伟目标,为应对后续用户激增的问题。特别安排了一次针对全体用户的秒杀活动:于XXXX年XX月XX日XX时XX分XX秒开始的秒杀五毛钱一百个QQ币的活动。每个账户仅限一次&#…...
小程序实现登录持久化
小程序实现登录持久化需要使用到小程序的缓存API,例如wx.getStorageSync()和wx.setStorageSync()等方法。以下是一个简单的代码实现: // App.js App({ // 在全局的App.js中定义全局变量userInfo,用于存放用户信息 globalData: { userInfo: …...

2023年亚太杯数学建模思路 - 案例:ID3-决策树分类算法
文章目录 0 赛题思路1 算法介绍2 FP树表示法3 构建FP树4 实现代码 建模资料 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法,就是频繁模…...
C复习-输入输出函数+流
参考: 里科《C和指针》 perror 定义在stdio.h中。当一个库函数失败时,库函数会在一个外部整型变量errno(在errno.h中定义)中保存错误代码,然后传递给用户程序,此时使用perror,会在打印msg后再打…...

duplicate复制数据库单个数据文件复制失败报错rman-03009 ora-03113
duplicate复制数据库单个数据文件复制失败报错rman-03009 ora-03113 搭建dg过程中,发现有一个数据文件在复制过程中没有复制过来,在备库数据文件目录找不到这个数据文件 处理方法: 第一步:主库备份86#数据文件 C:\Users\Admi…...

golang 解析oracle 数据文件头
package mainimport ("encoding/binary""fmt""io""os" ) // Powered by 黄林杰 15658655447 // Usered for parser oracle datafile header block 1 .... // oracle 数据文件头块解析 // KCBlockStruct represents the structure of t…...
van-popup滑动卡顿并且在有时候在ios上经常性滑动卡顿的情况
解决”pc端页面可以滚动,移动端手势无法滚动“问题的一次经历 - 掘金 <van-popup v-model"studentclassShow" :lock-scroll"false" position"bottom" style"z-index: 3000" :style"{ height: 55% }"><d…...

YOLOv7独家原创改进:最新原创WIoU_NMS改进点,改进有效可以直接当做自己的原创改进点来写,提升网络模型性能精度
💡该教程为属于《芒果书》📚系列,包含大量的原创首发改进方式, 所有文章都是全网首发原创改进内容🚀 💡本篇文章为YOLOv7独家原创改进:独家首发最新原创WIoU_NMS改进点,改进有效可以直接当做自己的原创改进点来写,提升网络模型性能精度。 💡对自己数据集改进有效…...
ubuntu20.04中编译zlib1.2.11(源码编译)
1. 安装cmake-gui 2. 下载并解压zlib-1.2.11,在解压得到的文件夹内部创建一个“build”文件夹。 3. 打开cmake-gui,配置zlib1.2.11的configure文件(主要编辑build路径,安装路径,以及其他依赖选项)&#x…...

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...