嵌入式學習筆記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
繁體地址,請注明出處:http://hk.pswp.cn/news/908282.shtml
英文地址,請注明出處:http://en.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;進而影響其他…