嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构

C/S (client/server  客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务器返回的结果;服务器端是提供服务的程序,一般部署在性能较强的计算机上,负责处理数据存储、业务逻辑计算等,监听特定端口等待客户端请求,接收到请求后进行处理并返回结果。

B/S(browser/server  浏览器/服务器):基于浏览器和服务器,客户端通过通用的浏览器(如 Chrome、Firefox、等)来访问应用程序。服务器端包括 Web 服务器和数据库服务器等,负责处理业务逻辑、存储和管理数据。

P2P(peer to peer 点对点):是一种去中心化的网络架构,网络中的节点(计算机)地位对等,不存在专门的中心服务器。每个节点既可以作为客户端向其他节点请求服务或资源,也可以作为服务器为其他节点提供服务或资源。

二、C/S 和 B/S 对比:

C/S架构B/S架构
客户端需要安装专用的客户端软件无需安装客户端,直接通过浏览器访问
协议可自定义私有协议(如游戏使用二进制协议),灵活性高。基于HTTP/HTTPS 协议,需遵循 Web 标准(如 RESTful 接口)。
功能
资源客户端分担部分计算压力,服务器专注数据处理,适合高并发、大数据量场景。所有逻辑在服务器端执行,需应对大量 HTTP 请求,对服务器性能要求高。

三、C/S通信流程

                       

服务器端流程

  • 创建套接字(socket ()):调用 socket() 函数创建一个套接字,这是进行网络通信的基础。它会返回一个套接字描述符,后续操作将基于这个描述符进行。该函数确定通信的协议族(如 AF_INET 表示 IPv4)、套接字类型(如 SOCK_STREAM 表示 TCP 流套接字)和协议(通常为 0,由系统根据前两个参数自动选择合适协议)。
  • 绑定地址和端口(bind ()):使用 bind() 函数将创建的套接字与特定的 IP 地址和端口号绑定。这样服务器就能明确在哪个地址和端口上监听客户端的连接请求。需要提供套接字描述符、指向包含 IP 地址和端口号信息的结构体指针,以及该结构体的大小。
  • 监听连接(listen ()):调用 listen() 函数使服务器进入监听状态,它会为套接字创建一个等待连接的队列,参数包括套接字描述符和队列的最大长度。这一步告诉系统开始接受客户端的连接请求。
  • 接受连接(accept ()):accept() 函数会阻塞(暂停执行),直到有客户端发起连接请求。一旦有客户端连接,它会创建一个新的套接字描述符用于与该客户端进行通信,同时返回客户端的地址信息。原来监听的套接字仍然保持监听状态,继续接受其他客户端的连接。
  • 读取数据(read ()):服务器通过新创建的与客户端通信的套接字描述符,使用 read() 函数读取客户端发送过来的数据。read() 函数从套接字接收数据并存储到指定的缓冲区中,返回实际读取的字节数。
  • 处理请求:服务器对读取到的数据进行相应的处理,例如解析请求内容、查询数据库、进行业务逻辑计算等。
  • 写入数据(write ()):处理完请求后,服务器使用 write() 函数将处理结果(响应数据)通过套接字发送回客户端。write() 函数将缓冲区中的数据写入套接字,发送给客户端。
  • 再次读取数据(read ()):服务器可能再次调用 read() 函数,等待接收客户端后续可能发送的数据,比如新的请求或确认信息等。
  • 关闭连接(close ()):通信结束后,服务器调用 close() 函数关闭与客户端通信的套接字,释放相关资源。

客户端流程

  • 创建套接字(socket ()):与服务器端一样,客户端首先调用 socket() 函数创建一个套接字,用于后续的网络通信,返回套接字描述符。
  • 建立连接(connect ()):客户端使用 connect() 函数尝试与服务器建立连接。需要指定要连接的服务器的 IP 地址和端口号,以及套接字描述符。如果服务器处于监听状态并且接受连接,连接就会成功建立;否则可能会返回错误。
  • 写入数据(write ()):连接建立后,客户端调用 write() 函数向服务器发送请求数据,将请求内容写入套接字,发送给服务器。
  • 读取数据(read ()):客户端调用 read() 函数从套接字读取服务器返回的响应数据,将数据存储到指定的缓冲区中。
  • 关闭连接(close ()):客户端完成与服务器的通信后,调用 close() 函数关闭套接字,释放资源。

整体交互过程

  • 服务器端先完成初始化(创建套接字、绑定、监听),进入等待客户端连接的状态。
  • 客户端创建套接字并尝试连接服务器,连接成功后,客户端向服务器发送请求数据。
  • 服务器接收请求数据,处理后向客户端发送响应数据。
  • 客户端接收响应数据,双方通信结束后各自关闭套接字,释放资源。

 注意:pid(进程ID)只能在本机范围内发送,两台主机间无法直接发送

四、TCP通信的特点

  • 有链接:并非一上来就直接进行传输,要先通过网络结点进行直接或者间接的连接,然后通过创建一些函数,连接起来(这条链路在通信过程中一直建立着)。
  • TCP是一种可靠传输:
  1. 应答机制:在 TCP 通信里,每次接收方收到数据,都会给发送方发送一个应答报文(ACK) 。TCP 通过给每个数据段编号(序列号),接收方根据收到的数据段序列号,在应答报文中用确认序号告知发送方哪些数据已正确接收。例如发送方发送了编号为 1 - 1000 的字节数据,接收方若正确收到,就在应答报文中带上确认序号 1001(表示期望接收的下一个字节编号),告知发送方 1 - 1000 已正确接收 。
  2. 超时重传:发送方发送数据后,会设定一个超时时间,若在该时间内未收到接收方的 ACK 应答报文,不管是数据包丢失还是 ACK 确认应答丢失,发送方都认为数据传输失败,会重新发送数据 。比如网络拥堵导致数据包在传输途中滞留,超过超时时间仍未到达接收方,或者接收方发送的 ACK 在返回途中丢失,发送方都感知不到数据已被接收,就会触发超时重传 
  • 全双工:通信双方都具备独立的发送和接收通道,发送数据同时可接收数据。比如在网络通信中,网卡支持全双工,数据发送线和接收线各自独立工作 ;发送和接收操作瞬时同步进行。以电话通信为例,通话时双方说话和听到对方声音同步,语音信号在两个方向同时传输 。
  • 连续:TCP 将数据视为无边界的连续字节流,发送方按顺序逐字节传输,接收方按序列号重组为连续的数据流。
  • 有顺序:TCP 为每个字节数据分配唯一序列号,接收方按序列号重组数据,确保字节流顺序正确;接收方通过 ACK 报文告知发送方已收到的数据序号,发送方仅传输未确认的分组,避免乱序。(udp本身不保证)。

五、“三次握手四次挥手 ”

                               

 三次握手:

       三次握手其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。

刚开始客户端处于 Closed 的状态,服务端处于 Listen 状态。


在socket编程中,客户端执行connect()时,将触发三次握手:

  • 第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN。此时客户端处于 SYN_SENT 状态 。首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。
  • 第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s)。同时会把客户端的 ISN + 1 作为ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_RCVD 的状态。在确认报文段中SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y。
  • 第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。确认报文段ACK=1,确认号ack=y+1,序号seq=x+1(初始为seq=x,第二个报文段所以要+1),ACK报文段可以携带数据,不携带数据则不消耗序号。

 

四次挥手: 

        建立一个连接需要三次握手,而终止一个连接要经过四次挥手(也有将四次挥手叫做四次握手的)。这由TCP的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。

TCP 连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),客户端或服务端均可主动发起挥手动作,

刚开始双方都处于ESTABLISHED 状态,假如是客户端先发起关闭请求。四次挥手的过程如下,在socket编程中,任何一方执行close()操作即可产生挥手操作:

  • 第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。

        即发出连接释放报文段(FIN=1,序号seq=u),并停止再发送数据,主动关闭TCP连            接,进入FIN_WAIT1(终止等待1)状态,等待服务端的确认。

  • 第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态。

       即服务端收到连接释放报文段后即发出确认报文段(ACK=1,确认号ack=u+1,序号             seq=v),服务端进入CLOSE_WAIT(关闭等待)状态,此时的TCP处于半关闭状态,         客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2(终止等待          2)状态,等待服务端发出的连接释放报文段。

  • 第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。

       即服务端没有要向客户端发出的数据,服务端发出连接释放报文段(FIN=1,ACK=1,         序号seq=w,确认号ack=u+1),服务端进入LAST_ACK(最后确认)状态,等待客户         端的确认。

  • 第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。

       即客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u+1,         ack=w+1),客户端进入TIME_WAIT(时间等待)状态。此时TCP未释放掉,需要经过

       时间等待计时器设置的时间2MSL后,客户端才进入CLOSED状态。

特性: tcp也叫流式套接字        

六、TCP服务端相关函数

socket()    创建套接字:

               

  • 参数
    • domain:协议族(如AF_INET表示 IPv4,AF_INET6表示 IPv6)。
    • type:套接字类型(如SOCK_STREAM表示 TCP 流式套接字,SOCK_DGRAM表示 UDP 数据报套接字)。
    • protocol:通常为 0,表示自动选择对应协议(如 TCP 对应IPPROTO_TCP)。
  • 返回值:成功返回套接字描述符(非负整数),失败返回-1并设置errno

bind()    绑定地址和端口 :

           

  • 参数
    • sockfdsocket()返回的套接字描述符。
    • addr:指向地址结构的指针(如struct sockaddr_in)。
    • addrlen:地址结构的长度(如sizeof(struct sockaddr_in))。
  • 返回值:成功返回0,失败返回-1

 listen()     监听连接:

            

  • 参数
    • sockfd:已绑定的套接字描述符。
    • backlog:未处理连接队列的最大长度(如5SOMAXCONN)。
  • 返回值:成功返回0,失败返回-1
  • 说明:将套接字从主动模式转为被动模式,等待客户端连接。

 accept()   接受客户端连接:

      

  • 参数
    • sockfd:监听套接字描述符(由listen()创建)。
    • addr:存储客户端地址的结构体指针(可为NULL)。
    • addrlen:地址结构体长度的指针(需初始化为结构体大小)。
  • 返回值:成功返回新的客户端套接字描述符,失败返回-1
  • 说明
    • 阻塞直到有客户端连接到达。
    • 返回的新套接字用于与客户端通信,原监听套接字继续监听

 connect()    连接服务器:

       

  • 参数
    • sockfd:客户端套接字描述符(由socket()创建)。
    • addr:服务器地址结构体指针。
    • addrlen:地址结构体长度。
  • 返回值:成功返回0,失败返回-1
  • 说明
    • 客户端调用此函数发起与服务器的连接(触发三次握手)。
    • 若连接失败(如服务器未监听),需重新调用connect()

 send()    发送数据:

         

  • 参数
    • sockfd:已连接的套接字描述符。
    • buf:待发送数据的缓冲区指针。
    • len:数据长度(字节)。
    • flags:通常为0,或设置特殊标志(如MSG_DONTWAIT表示非阻塞)。
  • 返回值:成功返回实际发送的字节数,失败返回-1
  • 说明
    • 数据可能未立即发送,而是存入发送缓冲区。
    • 返回值可能小于len(如网络拥塞),需循环发送剩余数据。

 

recv()    接收数据 :

          

  • 参数
    • sockfd:已连接的套接字描述符。
    • buf:存储接收数据的缓冲区指针。
    • len:缓冲区最大长度。
    • flags:通常为0,或设置特殊标志(如MSG_PEEK表示查看但不取出数据)。
  • 返回值
    • 成功返回实际接收的字节数。
    • 返回0表示对方已关闭连接(FIN 包)。
    • 返回-1表示出错(如连接断开)。
  • 说明
    • 若无数据且未关闭连接,recv()默认阻塞。
    • 需循环读取直至数据全部接收(尤其对于大文件)。

 close()    关闭套接字:

                  

  • 参数
    • fd:套接字描述符。
  • 返回值:成功返回0,失败返回-1
  • 说明
    • 关闭套接字并释放资源。
    • 触发 TCP 四次挥手断开连接(若为主动关闭方)。

七、代码实现 

  • 服务端
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h> /* See NOTES */
#include <time.h>
#include <unistd.h>
typedef struct sockaddr*(SA);
int main(int argc, char** argv)
{//监听套接字int listfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == listfd){perror("socket");return 1;}// man 7 ipstruct sockaddr_in ser, cli;bzero(&ser, sizeof(ser));bzero(&cli, sizeof(cli));ser.sin_family = AF_INET;ser.sin_port = htons(50000);ser.sin_addr.s_addr = inet_addr("127.0.0.1");int ret = bind(listfd, (SA)&ser, sizeof(ser));if (-1 == ret){perror("bind");return 1;}// 三次握手的排队数  ,listen(listfd, 3);socklen_t len = sizeof(cli);//通信套接字int conn = accept(listfd, (SA)&cli, &len);if (-1 == conn){perror("accept");return 1;}while (1){char buf[256] = {0};// ret >0 实际收到的字节数//==0  表示对方断开// -1 出错。ret = recv(conn, buf, sizeof(buf), 0);if(ret<=0){break;}printf("cli:%s\n",buf);time_t tm;time(&tm);struct tm * info = localtime(&tm);sprintf(buf,"%s %d:%d:%d\n",buf, info->tm_hour,info->tm_min,info->tm_sec);send(conn,buf,strlen(buf),0);}close(conn);close(listfd);// system("pause");return 0;
}
  • 客户端 
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h> /* See NOTES */
#include <time.h>
#include <unistd.h>
typedef struct sockaddr*(SA);
int main(int argc, char** argv)
{int conn = socket(AF_INET, SOCK_STREAM, 0);if (-1 == conn){perror("socket");return 1;}// man 7 ipstruct sockaddr_in ser, cli;bzero(&ser, sizeof(ser));bzero(&cli, sizeof(cli));ser.sin_family = AF_INET;ser.sin_port = htons(50000);ser.sin_addr.s_addr = inet_addr("127.0.0.1");int ret = connect(conn,(SA)&ser,sizeof(ser));if(-1 == ret){perror("connect");return 1;}while (1){char buf[256] = {0};strcpy(buf,"this is tcp test");send(conn,buf,strlen(buf),0);ret = recv(conn, buf, sizeof(buf), 0);if(ret<=0){break;}printf("ser:%s",buf);fflush(stdout);sleep(1);}close(conn);// system("pause");return 0;
}

八、黏包问题 

1.什么是粘包问题?

答:粘包问题是指在TCP通信中,发送方发送的多个独立消息在接收方被合并成一个消息接收的现象。换句话说,发送方发送的多条消息在接收方被“粘”在一起,导致接收方无法直接区分消息的边界。

2.粘包问题成因?
  • TCP是面向流的协议,它将数据视为一个连续的字节流,不保留消息的边界。
  • 发送方发送的多个消息可能被合并到同一个TCP包中发送。
  • 接收方在读取数据时,无法直接知道哪些字节属于哪条消息。
3.粘包问题的影响?
  • 接收方无法正确解析消息,可能导致数据解析错误。
  • 系统的健壮性和可靠性降低,尤其是在需要严格消息边界的应用中。
4.如何解决?
  • 添加分隔符:在每条消息末尾添加特殊分隔符(如\n\r\n),接收方通过分隔符来解析消息。
  • 固定大小:每条消息的长度固定,接收方根据固定长度来解析消息。
  • 自定义协议

九、练习

客户端-服务端  传送文件

  • 服务端
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h> /* See NOTES */
#include <time.h>
#include <unistd.h>
typedef struct sockaddr*(SA);
typedef struct
{char filename[256];char buf[1024];int buf_len;int total_len;
} PACK;
int main(int argc, char** argv)
{//监听套接字int listfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == listfd){perror("socket");return 1;}// man 7 ipstruct sockaddr_in ser, cli;bzero(&ser, sizeof(ser));bzero(&cli, sizeof(cli));ser.sin_family = AF_INET;ser.sin_port = htons(50000);ser.sin_addr.s_addr = inet_addr("127.0.0.1");int ret = bind(listfd, (SA)&ser, sizeof(ser));if (-1 == ret){perror("bind");return 1;}// 三次握手的排队数  ,listen(listfd, 3);socklen_t len = sizeof(cli);//通信套接字int conn = accept(listfd, (SA)&cli, &len);if (-1 == conn){perror("accept");return 1;}int first_flag = 0;int fd = -1;int current_size = 0;int total_size = 0;while (1){PACK pack;bzero(&pack, sizeof(pack));ret = recv(conn, &pack, sizeof(pack), 0);if (0 == first_flag){first_flag = 1;fd = open(pack.filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);if (-1 == fd){perror("open");return 1;}total_size = pack.total_len;}if (0 == pack.buf_len){break;}write(fd, pack.buf, pack.buf_len);current_size += pack.buf_len;printf("%d/%d\n", current_size, total_size);bzero(&pack, sizeof(pack));strcpy(pack.buf,"go on");// send(conn,&pack,sizeof(pack),0);}close(conn);close(listfd);close(fd);// system("pause");return 0;
}
  • 客户端
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h> /* See NOTES */
#include <sys/types.h>
#include <time.h>
#include <unistd.h>typedef struct sockaddr*(SA);
typedef struct
{char filename[256];char buf[1024];int buf_len;int total_len;
} PACK;
int main(int argc, char** argv)
{int conn = socket(AF_INET, SOCK_STREAM, 0);if (-1 == conn){perror("socket");return 1;}// man 7 ipstruct sockaddr_in ser, cli;bzero(&ser, sizeof(ser));bzero(&cli, sizeof(cli));ser.sin_family = AF_INET;ser.sin_port = htons(50000);ser.sin_addr.s_addr = inet_addr("127.0.0.1");int ret = connect(conn, (SA)&ser, sizeof(ser));if (-1 == ret){perror("connect");return 1;}PACK pack;strcpy(pack.filename, "1.png");  // /home/linux/1.pngstruct stat st;ret = stat("/home/linux/1.png", &st);if (-1 == ret){perror("stat");return 1;}pack.total_len = st.st_size;  // total sizeint fd = open("/home/linux/1.png", O_RDONLY);if (-1 == fd){perror("open");return 1;}while (1){pack.buf_len = read(fd, pack.buf, sizeof(pack.buf));send(conn, &pack, sizeof(pack), 0);if (pack.buf_len <= 0){break;}bzero(&pack,sizeof(pack));//recv(conn,&pack,sizeof(pack),0);usleep(1000*10); //10ms}close(conn);close(fd);// system("pause");return 0;
}

 

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

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

相关文章

抛砖引玉:RadarDet4D,NuScenes数据集Radar模态目标检测第二名(即将开源)

这几年一直在关注自动驾驶3D目标检测相关的研究。在NuScenes数据集上有很多经典的模型被提出并得到了验证&#xff0c;纯视觉3D目标检测经典的方法有BEVFormer、BEVDet系列、DETR3D、Sparse4D等工作&#xff0c;基于LiDAR的有CenterPoint、多模态有BEVFusion、DAL、UniTR等。 …

更新Java的环境变量后VScode/cursor里面还是之前的环境变量

最近我就遇到这个问题&#xff0c;这个一般是安装了多个版本的Java&#xff0c;并设置好环境变量&#xff0c;但VScode/cursor内部环境变量却没有改变 解决办法 打开设置&#xff0c;或者直接快捷键CTRL&#xff0c;搜索Java:Home编辑settings.json文件 把以下部分改为正确的…

线程的基础知识

进程和线程的区别&#xff1f; 从实例去引入我们的进程和线程的概念&#xff0c;说出进程和线程的关系&#xff0c;引出线程&#xff0c;说出两者的内存分配占用&#xff0c;上下文切换的区别 当操作系统把我们磁盘中的程序加载到我们的内存当中&#xff0c;为其分配内存空间&a…

x86 汇编中的【条件跳转指令】:从基础到扩展的全面解析(查表版)

为了彻底覆盖 x86 架构中所有条件跳转指令&#xff0c;包括 8086 到现代 x86-64 的全部变体&#xff0c;我重新整理了分类体系&#xff0c;并补充了鲜为人知的指令变体、操作数大小前缀和历史演进。 本文需要运用的知识(需要详细了解可点击对应的点)&#xff1a; flags寄存器…

FPGA点亮ILI9488驱动的SPI+RGB接口LCD显示屏(一)

FPGA点亮ILI9488驱动的SPIRGB接口LCD显示屏 ILI9488 RGB接口初始化 目录 前言 一、ILI9488简介 二、3线SPI接口简介 三、配置寄存器介绍 四、手册和初始化verilog FPGA代码 总结 前言 ILI9488是一款广泛应用于嵌入式系统和电子设备的彩色TFT LCD显示控制器芯片。本文将介…

Git忽略规则.gitignore不生效解决

我在gitlab中新建了一个项目仓库&#xff0c;先把项目文件目录绑定到仓库&#xff0c;并全部文件都上传到了仓库中。 然后又从别的项目复制了忽略文件配置过来&#xff0c;怎么搞他都不能生效忽略我不要提交仓库的文件。 从网上查到说在本地仓库目录中&#xff0c;打开命…

记一个判决书查询API接口的开发文档

一、引言 在企业风控、背景调查、尽职调查等场景中&#xff0c;判决书查询是一个非常重要的环节。通过判决书查询&#xff0c;可以了解个人或企业的司法涉诉情况&#xff0c;为风险评估提供数据支持。本文将详细介绍如何开发和使用一个司法涉诉查询API接口&#xff0c;包括客户…

mac版excel如何制作时长版环形图

设置辅助列 创建簇状柱形图 将辅助列绘制在次坐标轴 工作时长在主坐标轴&#xff0c;右键分别更改图表类型为圆环。 辅助列圆环全部为灰色&#xff0c;边框为白色 辅助列设置透明度100% 设置辅助列和工作时长列同样的圆环大小 可得 核心&#xff1a;只要辅助列边框不透明…

贪心算法应用:埃及分数问题详解

贪心算法与埃及分数问题详解 埃及分数&#xff08;Egyptian Fractions&#xff09;问题是数论中的经典问题&#xff0c;要求将一个真分数表示为互不相同的单位分数之和。本文将用2万字全面解析贪心算法在埃及分数问题中的应用&#xff0c;涵盖数学原理、算法设计、Java实现、优…

量化面试绿皮书:1. 海盗分金博弈

文中内容仅限技术学习与代码实践参考&#xff0c;市场存在不确定性&#xff0c;技术分析需谨慎验证&#xff0c;不构成任何投资建议。 1. 海盗分金博弈 五个海盗抢走了一个装满 100 枚金币的箱子。作为一群民主的海盗&#xff0c;他们同意以下分配战利品的方法:最资深的海盗将…

购物商城网站 Java+Vue.js+SpringBoot,包括商家管理、商品分类管理、商品管理、在线客服管理、购物订单模块

购物商城网站 JavaVue.jsSpringBoot&#xff0c;包括商家管理、商品分类管理、商品管理、在线客服管理、购物订单模块 百度云盘链接&#xff1a;https://pan.baidu.com/s/10W0kpwswDSmtbqYFsQmm5w 密码&#xff1a;68jy 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在…

用mediamtx搭建简易rtmp,rtsp视频服务器

简述&#xff1a; 平常测试的时候搭建rtmp服务器很麻烦&#xff0c;这个mediamtx服务器&#xff0c;只要下载就能运行&#xff0c;不用安装、编译、配置等&#xff0c;简单易用、ffmpeg推流、vlc拉流 基础环境&#xff1a; vmware17&#xff0c;centos10 64位&#xff0c;wi…

Java 高频面试题场景(二):老年健康手环数据管理系统

系列文章 序号文章名称1Java 高频面试题场景(一):社区智能充电桩管理系统2Java 高频面试题场景(二):老年健康手环数据管理系统文章目录 系列文章一、项目信息项目介绍技术栈主要工作二、面试题及回答1. **面试官问**:在这个老年健康手环数据管理系统项目中,为什么要用R…

Python爬虫爬取天猫商品数据,详细教程【Python经典实战项目】

Python爬取天猫商品数据详细教程 一、前期准备 1. 环境配置 Python环境&#xff1a;确保已安装Python 3.x版本&#xff0c;建议使用Anaconda或直接从Python官网下载安装。第三方库&#xff1a; requests&#xff1a;用于发送HTTP请求。BeautifulSoup&#xff1a;用于解析HTM…

Symbol as Points: Panoptic Symbol Spotting via Point-based Representation

文章目录 AbstractIntroductionRelated WorkVector Graphics RecognitionPanoptic Symbol SpottingPoint Cloud Segmentation MethodFrom Symbol to PointsPrimitive positionPrimitive feature Panoptic Symbol Spotting via Point-based RepresentationBackboneSymbol Spotti…

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…

[闭源saas选项]Pinecone:为向量数据库而生的实时语义搜索引擎

目录 Pinecone&#xff1a;为向量数据库而生的实时语义搜索引擎 一、什么是 Pinecone&#xff1f; 二、Pinecone 是开源的吗&#xff1f;支持私有化部署吗&#xff1f; 三、为什么需要向量搜索&#xff1f; 四、Pinecone 的核心优势 五、使用 Pinecone 的典型流程 六、在…

【Maniskill】使用Ppo的官方基线训练时出现指标突然“塌陷”的现象

1. 问题描述 1.1 在使用官方代码进行训练的时候“success_once突然掉落到0” 简要说明你在使用官方 examples/baselines/ppo/baselines.sh 脚本训练 PickCube-v1 时&#xff0c;在 early stage&#xff08;如前 50 k 步&#xff09;指标正常、success_once 接近 1&#xff0c;…

本地部署大模型实战:使用AIStarter一键安装Ollama+OpenWeb教程(含最新版本更新指南)

大家好&#xff01;今天给大家带来一个本地部署大模型的详细教程 &#xff0c;主要介绍如何通过 AIStarter 4.0 一键部署 Ollama OpenWeb 的完整流程。如果你还在为在线大模型不稳定、隐私泄露等问题烦恼&#xff0c;那么本地部署 将是一个非常不错的选择&#xff01; 首先&am…

Redis大量key集中过期怎么办

当 Redis 中存在大量 key 在同一时间点集中过期时&#xff0c;可能会导致以下问题&#xff1a; 请求延迟增加&#xff1a;Redis 在处理过期 key 时需要消耗 CPU 资源&#xff0c;如果过期 key 数量庞大&#xff0c;会导致 Redis 实例的 CPU 占用率升高&#xff0c;进而影响其他…