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

【C语言】socket编程接收问题

一、recv()函数接收到的返回值为0表示对端已经关闭

在TCP套接字编程中,通过recv()函数接收到的返回值为0通常表示对端已经关闭了套接字的发送部分。这是因为TCP是一个基于连接的协议,其中有定义明确的连接建立和终止流程;当对端调用close()或者shutdown(socket, SHUT_WR)来关闭套接字或其发送部分时,本端的recv()函数将返回0。
在大多数情况下,接收到0个字节足够用作连接终止的信号。一个好的实践是检查recv()是否返回0,并随后关闭套接字。
额外使用send()来确认连接的关闭并不是一个通用的解决方案。尝试向一个已经报告连接关闭的套接字发送数据可能会导致不符合预期的行为。例如:
1. 如果另一方关闭了连接,send()将可能导致SIGPIPE信号的生成,该信号默认会终止应用程序,除非信号被捕获或者使用send函数的MSG_NOSIGNAL标志。
2. send()可能返回-1并设置errno为EPIPE,表示对端套接字被关闭。
3. 在某些情况下(就像网络问题或关闭时的临时状态),send()可能会成功(返回非零值),在这种情况下,并不能使用它来判断对端是否关闭了连接。
对于验证TCP连接是否确实被关闭,建议的方式通常是:
- 监控输入流。如果recv()返回0,则对端正常关闭了连接。
- 在接收0后,可以调用shutdown()来禁用套接字的接收部分,或直接调用close()来关闭套接字,并进行必要的资源清理。
总而言之,如果recv()返回0,则可以合理地假设对端的套接字已被关闭,没有必要进一步使用send()来做确认。不过,连接异常关闭(如网络故障、对端崩溃等)的情况除外,这些情况可能需要通过错误检测机制(例如心跳包、超时检测等)来处理。

二、recv() 函数返回 0时,UDP和TCP对比

在 Linux 和大多数操作系统上,使用 TCP 协议的 sokcet 编程时,recv() 函数返回 0 通常表示连接已经被对端正常关闭(graceful shutdown)。这意味着对端调用了 close() 或者 shutdown(),并发送了一个完整的 TCP FIN 分组来优雅关闭连接。
对于 TCP 套接字来说,无法发送长度为 0 的数据包,因为 TCP 是一个面向流的协议,它没有消息边界。所以,如果发送方调用 send() 或 sendto() 函数,即使指定了长度为 0,也不会发送任何数据包,接收方也就不会在 recv() 调用中返回 0。
UDP 协议是不同的,它是一个基于消息(datagram)的协议,发送方可以发送一个空的数据报,这时候接收端的 recv() 或 recvfrom() 会返回 0,但这并不代表连接关闭,因为 UDP 是无连接的协议。在这种情况下,返回 0 就是实际接收到的数据长度,而不是一个连接关闭的指示。
如果在使用 TCP 协议中接收到了 recv() 返回的 0,可以安全地假定对端已关闭连接。如果处理的是 UDP,那么需要根据上下文来判断,因为这只是表明这个特定的数据包是空的,并不表示后续不会有数据到来或者远端已经关闭。

三、为什么使用recv而不是recvfrom接收TCP数据?

在编程中使用 recv 和 recvfrom 函数是针对套接字(socket)中数据传输的两种不同的情况。这两个函数通常用在网络编程中,它们都属于 BSD sockets API,用于从套接字接收数据,但它们的应用场景和具体行为有所不同。

1. recv:

   recv 函数用于接收一个已经连接的套接字(通常是TCP套接字)上的数据。它的原型如下(以C语言为例):

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

   其中,sockfd是指向一个已建立连接的套接字的文件描述符,buf是接收数据的缓冲区,len是缓冲区的大小,flags是一组指定接收行为的标志,位掩码。

2. recvfrom:

   recvfrom 函数通常用于无连接的套接字(如UDP套接字),可以接收数据并获取发送方的地址。其原型如下:

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

    recvfrom 与 recv 相比多出两个参数:src_addr是发送方地址结构的指针,addrlen是地址长度的指针。这使得 recvfrom 能够在接收数据的同时,返回发送方的地址信息。
   对于已经连接的套接字(TCP),recv可以确定数据的来源,因此不需要 src_addr 和 addrlen 参数。但是对于未连接的套接字(UDP),这些参数允许接收方得知每个数据报的源地址信息。

当处理TCP数据时,通常使用 recv 函数,而不是 recvfrom,主要出于以下原因:
- 在TCP传输中,一旦客户端与服务器建立了连接,数据的发送和接收方地址就是确定的。因此,没有必要在每次调用接收函数时都提供地址信息,这可以简化代码并提高效率。
- TCP是一个面向连接的协议,它通过三次握手过程来建立连接。`recv` 更适合接收已经建立连接的、来自特定远端的数据。
- 使用 recv 可以使TCP代码更清晰和直接,而使用 recvfrom 可能会造成混乱,因为它更多地用于处理无连接协议,比如UDP。
- recv 的参数比 recvfrom 少(不需要地址参数),这在已连接的TCP流量中可以减少不必要的参数管理。
简而言之,在处理TCP数据时,推荐使用 recv,因为它正是为处理已连接的流式(stream)套接字设计的。相反,recvfrom用于无连接的数据报(datagram)套接字,它提供了获取发送方信息的能力,这在处理UDP数据时是必要的。

四、为什么通常使用recvfrom接收UDP数据

对于 UDP —— 一个无连接的协议 —— 接收函数需要能够处理来自不同发送方的数据包,并能提供发送者的信息。recvfrom是设计用来处理这种情况的,因为它允许你接收数据和源地址信息。在 UDP 通信中,每个接收到的数据包可能来自不同的发送方,而 recvfrom 可以知道每个数据包来自哪里。
反之,recv 函数虽然也可以用于 UDP,但它不提供这种灵活性,因为它无法返回发送方地址。所以,即便在技术上可以用 recv 接收 UDP 数据,但在实际应用中,使用 recvfrom 通常更加合适和直接。

在使用socket进行网络编程时,接收UDP数据包确实可以只用recv函数,而不需要获取发送方的地址信息。recv函数允许从与socket关联的连接中接收数据,但不提供关于数据包来源的信息。
不过,UDP作为一种无连接的协议,通常会使用recvfrom函数,它允许接收方在接收数据时同时获取发送方的地址信息。这是因为UDP数据包是独立的消息,每个数据包都可能来自不同的发送方,而知道每个数据包的来源是很重要的,尤其是在服务器需要处理来自多个客户端的数据的场景中。
例如,一个使用UDP的回声服务器需要能够接收来自许多不同客户端的消息,并将相应的回复发送回正确的发送方。在这种情况下,如果不使用recvfrom来获取发送方的具体地址信息,服务器则无法知道该将响应发送给哪个客户端。
如果应用场景中,服务器只接收来自一个固定来源的数据,或者发送方的地址信息并不重要,那么使用recv可能是可以接受的。但在大多数情况下,了解数据包的来源很重要,因为它可以帮助应用程序处理各种网络事件,包括数据路由、认证、日志记录或其他基于网络信息的操作。
总而言之,使用recvfrom而不仅是recv,主要是因为UDP是一种无连接的、面向消息的协议,每个数据包都是独立传输的,并且通信的双方没有固定的连接状态。获取发送方的地址信息对于确保数据能够被正确处理和响应是非常重要的。 

五、错误检测

在网络编程中,对端套接字的关闭通常通过recv()函数返回0来检测,表明对端执行了正常的套接字关闭操作。但是,如果连接异常关闭(如网络故障、对端崩溃等),这种情况下recv()可能返回-1或者遇到ECONNRESET错误。这时需要实现一套更健壮的错误检测机制来监控和处理这类情况,以下是一些常见的方法:

1. 心跳机制(Keepalive):

   心跳是一种定期发送的轻量级数据包,用以检测对端是否仍然响应。如果一定时间内没有接收到心跳响应,那么可以认为对端可能出现了问题。心跳包常用于检测半开连接或非活动连接。
   在TCP中,你可以通过设置套接字选项启用TCP的keepalive机制:

   int optval = 1;setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));

 TCP的keepalive机制是一种检测对端是否仍然可达的功能,其在网络编程中被用来监测TCP连接是否断开,但没有正常关闭。如果启用了keepalive,即使没有数据传输,TCP也会定期发送探测包以保持连接的活跃状态。如果在多次探测后没有收到响应,则认为对端不可达,连接将被终止。
启用TCP keepalive的影响:
检测到死连接:启用keepalive可以帮助您检测到网络断开或对端崩溃等情况,这些情况下数据传输已经停止但对端没有正确关闭TCP连接。
节省资源:通过检测和关闭无用的连接,可以更有效地利用服务器资源,例如端口和内存。
透明重连: 在某些场合,如果检测到连接断开,应用程序可能希望自动重新建立连接,这在启用了keepalive的情况下更容易实现。
编程处理的差异:
设置了TCP keepalive后,一般不需要在程序中作出特别处理。TCP堆栈自动处理keepalive,包括发送探针和检测死链。程序只需关注正常的I/O操作即可。然而,有两点值得注意:
异常处理:keepalive探测发现连接已死时,TCP堆栈会断开连接。这将导致任何试图通过这个套接字进行读写操作的尝试失败,并产生异常或错误。程序需要能够捕获并妥善处理这些错误。
keepalive参数配置:某些操作系统允许进一步自定义keepalive行为,如探测频率、重试次数和空闲时间等。可以通过类似`setsockopt()`的调用进行更细节的设置。
例如,在Linux上,可以设置更多的keepalive选项:

int keepalive = 1; // 开启keepalive属性
int keepidle = 60; // 若60秒内没有任何数据交互,则进行探测
int keepinterval = 5; // 探测时发探测包的时间间隔为5秒
int keepcount = 3; // 探测尝试的次数。如果第1次探测包就收到响应则后2次的不再发。setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive , sizeof(keepalive));
setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepidle , sizeof(keepidle));
setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepinterval , sizeof(keepinterval));
setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcount , sizeof(keepcount));

请注意,根据使用的操作系统和网络库,API的确切名称和参数可能会有所不同。另外,不应当滥用keepalive,因为即使是空闲连接,也会增加网络流量并消耗一定的服务器资源。适当使用keepalive能够为网络程序增加一层鲁棒性,但也需要在性能和资源使用之间找到平衡点。

2. 超时检测(Timeout):

   对于连接和读写操作,可以设置超时时间。如果在指定时间内没有数据传输,那么可以假定有错误发生,连接可能已失效,然后关闭连接。
   setsockopt()函数同样可以用来为`recv()`设置超时:

   struct timeval tv;tv.tv_sec = 10;  // 10秒超时tv.tv_usec = 0;setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval));

3. 应用层确认消息:

   对于某些协议,可能需要在应用层实现确认(ACK)机制。每次数据传输完毕时,接收方都需要发送一个确认消息给发送方。如果发送方在设定的超时时间内没有收到确认消息,它将重试发送该数据或断开连接。

4. 重试策略:

   如果操作(如连接请求或数据发送)失败,可以采取重试策略,在每次重试之间增加延时,这通常被称为指数退避。

5. 异常检测和状态监控:

   在多线程或异步编程中,可以使用一个监控线程或服务来检测客户端和服务端的异常状态,并响应相应的错误。这可能涉及到周期性地检查套接字的连接状态,或者实现更复杂的状态机制来管理连接。
实现这些机制时,需要考虑到检测频率和网络开销的权衡,以及如何在检测到异常时采取有效的恢复措施。另外,还需要确保任何状态或数据的同步操作在多线程环境中是线程安全的。在多线程或异步编程中,使用一个监控线程或服务来检测客户端和服务端的异常状态是一种常见的设计模式,它可以帮助维护系统的健壮性。以下是一般用于实现这种监控功能的步骤:
1. 定义健康检查API:
   为客户端和服务端实现标准的健康检查API。这些API可以返回简单的状态码或更复杂的健康信息,以便监控服务可以理解被监控服务的状态。
2. 设置监控服务:
   实现一个监控服务或线程,定期向客户端和服务端发出健康检查请求。监控频率可以根据应用场景和系统需求来决定。
3. 检测并记录状态:
   监控服务接收到健康检查的响应后,记录客户端和服务端的状态。如果发现异常状态,应记录详细信息,以备分析和问题排查。
4. 触发报警和响应:
   当检测到异常状态时,监控服务会触发报警。报警可以是日志、电子邮件、短信或者集成企业监控系统的通知。同时,监控服务可以根据设定的策略执行响应动作,比如重启服务、断开客户端连接或者将任务转移到备用服务。
5. 实现异常恢复逻辑:
   当检测到异常时,除了报警之外,可以设置策略和逻辑来试图自动恢复服务。例如,如果是一个临时的网络问题,可能只需要重试连接;如果服务崩溃了,可能需要自动重启服务等。
6.优雅地处理并发问题:
   因为涉及到多线程或异步操作,监控服务自身应当能够优雅地处理并发问题,比如使用线程安全的数据结构,合理地加锁,以及使用并发编程的最佳实践。
一个简单的监控线程示例如下:

import threading
import requests
import time# 健康检查函数
def health_check(target_url):try:response = requests.get(target_url)if response.status_code == 200:print(f"{target_url} is healthy.")else:print(f"Warning: {target_url} returned status code {response.status_code}")# 处理异常情况,例如重启服务、发送报警等handle_error(target_url, response.status_code)except requests.RequestException as e:print(f"Error checking {target_url}: {e}")# 处理连接错误handle_error(target_url, 'connection error')# 异常处理函数
def handle_error(target_url, error):# 这里添加异常处理逻辑pass# 监控线程主逻辑
def monitor_thread(targets, interval):while True:for target in targets:health_check(target)time.sleep(interval)# 启动监控线程
targets = ['http://service1/api/health', 'http://service2/api/health']
monitoring_interval = 30  # 检查间隔为30秒# 在后台启动监控线程
monitor_thread = threading.Thread(target=monitor_thread, args=(targets, monitoring_interval))
monitor_thread.daemon = True
monitor_thread.start()# 主程序可以继续进行其他工作
# ...

上面的Python代码示例创建了一个在后台运行的监控线程,该线程会定期检查一组服务地址的健康状况,并根据服务的状态执行错误处理逻辑。
这只是一个监控机制的简单实现,适用于不需要复杂监控策略的小型系统。在实际应用中,可能需要使用更完善和健壮的监控系统,如Prometheus、Nagios、Zabbix等,以及与之配套的报警系统如Alertmanager。 
在多线程或异步编程中,异常状态通常确实是指应用层面的,而非底层网络或操作系统层面的。应用层的异常状态是指由程序逻辑或程序运行时引起的异常状况,这些异常状况可能需要特殊处理,包括但不限于:
1. 超时错误:当客户端发起请求时,如果服务端在特定的时间内没有作出响应,可能会触发超时异常。
2. 服务不可用:当服务端因为各种原因(如维护、崩溃、过载)无法提供服务时。
3. 资源枯竭:例如,线程池或连接池用完,或者系统内存、CPU资源不足。
4. 功能错误:服务端在处理请求时发生逻辑错误,返回错误的结果。
5. 协议错误:违反应用层协议或错误的数据格式,可能导致无法正确解析请求或响应。
监控线程或服务会在这些异常状态发生时进行以下操作:
- 记录和通知:它会记录异常状态的详细信息,并可能通过邮件、短信或者其他方式通知开发者或系统管理员。
- 尝试恢复:对于一些已知的异常状态(例如,临时的网络问题),监控服务可能尝试重新启动服务或重新发起请求。
- 自动扩容:当服务因为负载过高无法处理额外的请求时,监控服务可能触发自动扩容机制,启动更多的服务实例以处理增加的请求负荷。
- 限流和降级:在系统资源有限或服务不稳定时,监控服务可能实现限流策略,减少服务的访问量,或者执行降级策略,保证核心业务不受影响。
- 故障隔离:当检测到服务异常时,监控服务可能会将异常的服务实例或节点隔离,防止故障扩散。
监控线程或服务是提高系统稳定性和可用性的重要组成部分。通过能够检测和响应应用层的异常状态,可以提前预防潜在的问题,或者在问题发生时迅速做出反应,从而最小化对用户的影响。 

在TCP通信中,当recv()调用返回0时,通常意味着对端的套接字已经正常关闭了其连接,即发送方执行了一个正常的关闭操作(调用了close()或shutdown())。这表明连接被正常地终止,没有遗留的数据未被接收。
如果连接异常关闭,如由于网络故障、对端应用程序崩溃、硬件故障等,那么recv()可能会表现不同。在这些情况下,如果异常发生在recv()之前,recv()可能会:
1. 阻塞,直到超时(如果有设置超时的情况),因为它在等待数据到达,但是由于连接已经失效,数据永远不会到达。
2. 返回一个错误,通常是通过抛出一个异常或返回一个特殊的错误码,这取决于所使用的编程语言和网络库。在Python的socket模块中,这通常会以一个socket.error异常的形式发生。
在某些系统上,当对端非正常关闭连接时(即发送了RST包而非正常的FIN包),recv()将返回一个错误而非0。处理这种情况的确切方式取决于特定的操作系统和网络栈实现。
为了确保网络程序的健壮性,编写网络代码时应当:
- 正确处理recv()返回0的情况,作为连接正常关闭的信号。
- 捕获和处理recv()过程中可能出现的异常或错误。
- 实现适当的心跳包、超时检测和重连策略,以便在连接丢失时能及时发现并采取相应措施。

六、recv函数终止应用程序

在Linux C语言socket编程中,recv函数通常不会直接终止应用程序。它是一个系统调用,用于从一个套接字中接收数据。如果出现错误或异常情况,recv会返回一个错误码,而不是终止应用程序。
然而,有一些情况可能导致应用程序异常结束或被终止,这些通常与recv的错误处理方式有关:
1. 未捕获的信号: 如果在recv调用过程中收到了一个信号,并且该信号没有被捕获或者其处理函数决定退出,那么应用程序可能会终止。常见的例子是SIGINT`(通常是由用户按下Ctrl+C产生)和SIGPIPE(在试图写入一个已关闭的连接时产生)。
2. 未检查的错误码: 如果recv由于某种错误返回了一个负的错误码,而应用程序没有正确检查并处理这个错误,那么接下来的操作可能会基于无效的数据工作并抛出其他错误,这有时会导致应用程序异常结束。
3. 非阻塞套接字: 如果套接字被设置为非阻塞模式,而且在调用recv时没有可读的数据,recv会返回一个错误(通常是EWOULDBLOCK或EAGAIN)。如果不适当地处理这种情况,应用程序可能会进入一个忙循环,可能导致程序使用大量CPU资源、变得不响应,甚至最终因为系统监控或管理员干预而被结束。
4. 程序逻辑错误: 如果在异常处理逻辑中存在错误,或者recv返回值的后续处理代码有问题,这些都可能导致应用程序崩溃。
在编写与recv相关的代码时,应该始终对返回值进行检查,对于任何可能的错误值都要有相应的错误处理逻辑。这样可以避免不必要的程序终止,并且确保在出现错误时能够有序地清理资源并提供适当的错误反馈。此外,理解和处理信号也是确保程序稳定运行的关键部分。 在使用Linux C语言进行socket编程时,处理recv函数的返回值时应当考虑三种主要的情况:
1. 数据成功接收: 当recv函数返回一个正整数时,这表明你成功地从对端接收到了这么多字节的数据。
2. 连接正常关闭: 当recv函数返回0时,这意味着对端已经关闭了连接。在这种情况下,应该结束对这个socket的操作,进行清理工作并关闭自己的socket。
3. 错误发生: 当recv函数返回-1时,这表明发生了一个错误。可以通过检查errno变量来获取错误的具体信息,并采取恰当的错误处理措施。
以下是一个简单的示例代码,展示了如何处理`recv`的不同返回值:

#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>#define BUFFER_SIZE 1024int main() {int socket_fd; // 假定这个socket已经被创建并连接到了一个服务端char buffer[BUFFER_SIZE];ssize_t bytes_received;// 接收数据bytes_received = recv(socket_fd, buffer, BUFFER_SIZE, 0);if (bytes_received > 0) {// 成功接收数据printf("Received %zd bytes: %s\n", bytes_received, buffer);} else if (bytes_received == 0) {// 对端关闭连接printf("Connection closed by peer.\n");} else {// 发生错误fprintf(stderr, "recv failed: %s\n", strerror(errno));if (errno == EAGAIN || errno == EWOULDBLOCK) {// 这可能是非阻塞socket的正常情况} else {// 处理其他错误类型,可能需要关闭socket}}// 关闭socketclose(socket_fd);return 0;
}

在上面的代码中,我们首先检查recv返回的字节数。如果返回的是一个正数,我们打印出接收到的数据。如果返回值是0,我们知道连接已经正常关闭。如果返回值是-1,我们使用strerror函数来打印错误信息。
在实际的网络应用程序中,可能还需要处理网络超时的情况,复杂的错误恢复逻辑,以及可能的非阻塞I/O操作。还需要注意,当在多线程环境中使用sockets时,需要考虑同步和并发问题。
错误处理很大程度上取决于具体的应用逻辑,但应该包括记录错误、尝试重新连接以及合适的时候关闭socket等逻辑。

七、UDP的sendto/recvfrom返回错误与TCP的不同

在Linux中使用C语言编写的UDP套接字编程中,UDP协议是无连接的,这意味着每个数据包独立发送,没有建立持久连接的概念。由于UDP不跟踪连接状态,因此即使对端套接字已关闭,sendto函数通常仍会成功返回而不是报错。
当您使用sendto发送一个UDP数据报时,数据报被发送到指定的目的地址和端口,但是发送方并不知道这个目的地是否有一个活跃的接收者。数据发送后,除非底层网络问题或目的地址错误导致网络栈返回错误,否则sendto通常只是将数据报提交给网络堆栈然后返回。
然而,如果发送到一个不存在的地址或端口上,并且操作系统能够立即确定这一点(例如,没有这样的网络),sendto可能会返回错误并设置errno,例如ENETUNREACH(网络不可达)或EHOSTUNREACH(无法到达主机)。
不过,如果多次向一个关闭的套接字发送数据,该网络协议可能会最终意识到没有接收方,并可能通过ICMP(Internet控制消息协议)消息如“目的地不可达”通知您的系统。但是,由于这个过程是异步的,sendto不会直接因此报错。
在Linux C语言socket编程中,处理UDP通信时,sendto() 和 recvfrom() 的行为与 TCP 有些不同,因为 UDP 是无连接的协议。
1. 如果使用 sendto() 向一个已经关闭的对端发送UDP数据:
由于UDP是无连接的协议,当使用 sendto() 发送数据时,并不会去检查对端是否存在或者已关闭。sendto() 通常会成功地返回发送的字节数,即使对端已关闭。不过,如果对端主机完全不存在或某些特定网络错误发生,可能会收到一个 ICMP 错误消息,但这通常不会通过sendto()本身报告,除非已经设置了socket选项来接收ICMP错误。
2. 如果在对端关闭后使用 recvfrom() 接收数据:
由于UDP是无连接的,所以即使发送方停止发送数据,recvfrom() 通常也不会报告错误,它将阻塞等待直到接收到新的数据报文,或者返回错误如果有本地错误发生(如套接字已被本地关闭)或者遇到超时(如果设置了非阻塞或超时选项)。recvfrom() 不会因为远程端点已关闭就返回错误,因为UDP协议本身根本不跟踪连接状态。
综上所述,由于UDP是无连接的,不能通过 sendto() 和 recvfrom() 来得知对端socket是否已经关闭。如果需要检查对端是否活跃,需要在应用层协议中实现心跳或其他机制来确认对端的状态。 

相关文章:

【C语言】socket编程接收问题

一、recv()函数接收到的返回值为0表示对端已经关闭 在TCP套接字编程中&#xff0c;通过recv()函数接收到的返回值为0通常表示对端已经关闭了套接字的发送部分。这是因为TCP是一个基于连接的协议&#xff0c;其中有定义明确的连接建立和终止流程&#xff1b;当对端调用close()或…...

Python与ArcGIS系列(二十)GDAL之合并shp和geojson要素图层

目录 0 简述1 代码实现2 结果展示0 简述 Shp格式是GIS中非常重要的数据格式,主要在Arcgis中使用,但在进行很多基于网页的空间数据可视化时,通常只接受GeoJSON格式的数据,众所周知JSON是利用键值对+嵌套来表示数据的一种格式,以其轻量、易解析的优点,被广泛使用与各种领域…...

CGAL5.4.1 边塌陷算法

目录 1、使用曲面网格的示例 2、使用默认多面体的示例 3、使用丰富多面体的示例 主要对1、使用曲面网格的示例 进行深度研究 CGAL编译与安装CGAL安装到验证到深入_cgal测试代码-CSDN博客 参考资料CGAL 5.4.5 - Triangulated Surface Mesh Simplification: User Manual …...

网络安全知识和华为防火墙

网络安全 网络空间安全 ---Cyberspace 2003年美国提出的网络空间概念 ---一个由信息基础设施组成的互相依赖的网络。 我国官方文件定义&#xff1a;网络空间为继海、陆、空、天以外的第五大人类互动领域。 通信保密阶段 --- 计算机安全阶段 --- 信息系统安全 --- 网络空间安…...

Docker 搭建MySQL主从复制-读写分离

一. 介绍 MySQL主从复制是一种常用的数据库高可用性解决方案&#xff0c;通过在主数据库上记录的数据变更&#xff0c;同步到一个或多个从数据库&#xff0c;实现数据的冗余备份和读写分离。在Docker环境下搭建MySQL主从复制和读写分离&#xff0c;不仅方便管理&#xff0c;还…...

[linux] which和find有什么区别?

which 和 find 都是 Unix/Linux 系统中的命令&#xff0c;但它们的用途和工作方式有很大的不同。 which 命令&#xff1a;which 命令是用来查找并显示用户可以在当前环境下执行的命令的完整路径。这些命令通常位于 PATH 环境变量中指定的目录中。例如&#xff0c;which python …...

使用Neo4j做技术血缘管理

目录 一、neo4j介绍 二、windows安装启动neo4j 2.1下载neo4j 2.2 解压文件 2.3 启动neo4j 三、neo4j基础操作 3.1 创建结点和关系 3.2 查询 3.3 更改 3.4 删除 四、技术血缘Demo实现 4.1 构建节点对象 4.2 构建存储对象 4.3 创建有属性关联关系 4.4 最后是图结果…...

Unity-WebGL

问题&#xff1a;提示gzip压缩报错解决&#xff1a;关闭打包的地方压缩&#xff0c;如下图问题&#xff1a;窗口未全屏解决&#xff1a;使用百分比画布替换固定尺寸画布 参考&#xff1a;新版Unity打包Webgl端进行屏幕自适应_unity webgl分辨率自适应-CSDN博客问题&#xff1a;…...

腾讯云部署vue+node项目

文章目录 一、安装宝塔二、vue项目部署三、node项目部署 前言: 关于项目部署,一开始也是找了很多资料,费了点时间,所以记录一下。希望能对各位有所帮助。 一、安装宝塔 1.首先在控制台,进入云服务器的终端界面 2.输入命令和密码获取权限,并且安装宝塔界面 yum install -y w…...

HBase表结构

HBase是非关系型数据库&#xff0c;是高可靠性、高性能、面向列、可伸缩、实时读写的分布式数据库。 HBase使用场景 大规模数据存储&#xff1a;如日志记录、数据库备份等。实时数据访问&#xff1a;如实时搜索、实时分析等。高性能读写&#xff1a;如高并发、低延迟的读写操…...

本人面试积累面试题更新中

本人面试积累面试题 1.事务的隔离级别 答:2024年1月30日 1.读已提交-----读取其他事务已经提交的数据 2.读未提交-----读取其他事务还未提交的数据–可能出现脏读 3.可重复读-----同一个事务多次读取同一个数据,尽可能的保证数据的一致性但是可能出现幻读 4.串行读------确保每…...

[经典面试题]169. 多数元素

题目描述 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 示例 1&#xff1a; 输入&#xff1a;nums [3,2,3] 输出&#xff1a;3…...

Wireshark网络协议分析 - TCP协议

在我的博客阅读本文 文章目录 1. 基础2. 实战2.1. 用Go写一个简单的TCP服务器与客户端2.2. Wireshark抓包分析2.3. 限制数据包的大小——MSS与MTU2.4. 保证TCP的有序传输——Seq&#xff0c;Len与Ack2.5. TCP头标志位——URG&#xff0c;ACK&#xff0c;PSH&#xff0c;RST&…...

3 款最好的电脑硬盘数据迁移软件

您将从本页了解 3 款最好的 SSD硬盘数据迁移软件&#xff0c;磁盘供应商提供的软件和可靠的第三方软件。仔细阅读本文并做出您的选择。 什么是数据迁移&#xff1f; 数据迁移是将数据移动到其他计算机或存储设备的过程。在日常工作活动中&#xff0c;常见的数据迁移有三种&…...

【Java之HTML】

HTML 概念 互联网的产生&#xff1a;w3c的成立&#xff0c; ​ 互联网最开始设计的目的&#xff1a;看论文 ---->浏览器&#xff0c;HTML ​ 网络三要素&#xff1a;HTML HTTP URL HTML描述论文的格式 HTTP标记这个论文在网络上怎么传输 URL:指示这个论文在互联网的哪…...

支付宝支付功能解析,从零到掌握,轻松享受便捷支付

目录 一、支付宝支付功能简介 1.1 支付宝支付的概念 1.2 支付宝支付的优势 1.3 支付宝支付的适用场景 二、支付宝支付的准备工作 三、支付宝支付的接入流程 四、支付宝支付的安全性 5.1 支付宝支付的安全机制 5.2 防范支付风险的措施 5.3 支付宝支付的安全技术保障 …...

MacOS安装反编译工具JD-GUI以及解决无法打开的问题

目录 一.下载地址 二.安装 三.问题 四.解决办法 1.显示包内容 2.找到Contents/MacOS/universalJavaApplicationStub.sh 3.修改sh文件 4.保存后再次打开即可 一.下载地址 Java Decompiler 二.安装 将下载下来的 jd-gui-osx-1.6.6.tar 解压&#xff0c;然后将 JD-GUI.a…...

SpringBoot将第三方的jar中的bean对象自动注入到ioc容器中

新建一个模块&#xff0c;做自动配置 config&#xff1a;需要准备两个类&#xff0c;一个自动配置类&#xff0c;一个配置类 CommonAutoConfig&#xff1a;此类用于做自动配置类它会去读取resoutces下的META-INF.spring下的org.springframework.boot.autoconfigure.AutoConfig…...

5.变量的解构赋值 - JS

什么是解构赋值 通过类似&#xff08;或相同&#xff09;的构型&#xff0c;将已知数据的元素/属性解构并提取出来&#xff0c;再赋值到相应变量&#xff0c;可以是新建的变量&#xff0c;也可以是已存在的变量/属性等&#xff1b;最常见的是数组和对象的解构赋值&#xff0c;…...

tableau添加形状

目录 1.效果&#xff1a;1.自带的形状&#xff1a;2.添加形状&#xff1a;小结&#xff1a; 1.效果&#xff1a; 1.自带的形状&#xff1a; 2.添加形状&#xff1a; 找到tableau的安装目录&#xff0c;点入 默认->形状 的文件夹&#xff1a; 新建一个文件夹&#xff1a; …...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

五、jmeter脚本参数化

目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...

轻量安全的密码管理工具Vaultwarden

一、Vaultwarden概述 Vaultwarden主要作用是提供一个自托管的密码管理器服务。它是Bitwarden密码管理器的第三方轻量版&#xff0c;由国外开发者在Bitwarden的基础上&#xff0c;采用Rust语言重写而成。 &#xff08;一&#xff09;Vaultwarden镜像的作用及特点 轻量级与高性…...

Unity-ECS详解

今天我们来了解Unity最先进的技术——ECS架构&#xff08;EntityComponentSystem&#xff09;。 Unity官方下有源码&#xff0c;我们下载源码后来学习。 ECS 与OOP&#xff08;Object-Oriented Programming&#xff09;对应&#xff0c;ECS是一种完全不同的编程范式与数据架构…...

SE(Secure Element)加密芯片与MCU协同工作的典型流程

以下是SE&#xff08;Secure Element&#xff09;加密芯片与MCU协同工作的典型流程&#xff0c;综合安全认证、数据保护及防篡改机制&#xff1a; 一、基础认证流程&#xff08;参数保护方案&#xff09; 密钥预置‌ SE芯片与MCU分别预置相同的3DES密钥&#xff08;Key1、Key2…...

Vue项目PDF目录功能集成【一】——方案深度思考

文章目录 项目背景一、方案一&#xff1a;数据透传 外部开发模式二、方案二&#xff1a;内置组件 黑盒模式三、方案三&#xff1a;激活官方实现 可控定制总结 项目背景 本项目是Vue 3 项目&#xff0c;需要使用文件预览组件&#xff08;pdfjs 当前是作为sdk二次封装引入&am…...

​​​​​​​6板块公共数据典型应用场景【政务服务|公共安全|公共卫生|环境保护|金融风控|教育科研]

1. 政务服务 1.1 城市规划与管理 公共数据在城市规划与管理中可发挥关键作用。通过汇聚自然资源、建筑物、人口分布等基础数据,构建数字孪生城市模型,辅助城市总体规划编制、决策仿真模拟。在城市基础设施建设、安全运营、应急管理等方面,公共数据也是不可或缺的基础支撑。例…...