嵌入式學習day34-網絡-tcp/udp

day33練習:


客戶端 與 服務器實現一個點對點聊天

tcp

客戶端

clifd = socket

connect

//收 --父進程 //發 --子進程 tcp

服務器 listenfd = socket

bind

listen

connfd = accept()

//收 -- 父進程 //發 -- 子進程

client.c

#include "../head.h"int res_fd[1]; // 只需要存儲客戶端socket文件描述符int tcp_client_connect(char const *ip,char const * port)
{int fd = socket(AF_INET,SOCK_STREAM,0);if (fd < 0){perror("socket fail");return -1;}res_fd[0] = fd; // 保存文件描述符用于清理printf("fd = %d\n",fd);struct sockaddr_in seraddr;//ip 192.168.0.150//port 50000bzero(&seraddr,sizeof(seraddr)); // 使用bzero清零seraddr.sin_family = AF_INET;seraddr.sin_port = htons(atoi(port)); //atoiseraddr.sin_addr.s_addr = inet_addr(ip);if ( connect(fd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){perror("connect fail");return -1;}return fd;
}// 信號處理函數
void do_handler(int signo)
{exit(0);
}// 清理函數
void cleanup(void)
{close(res_fd[0]);printf("pid = %d ---cleanup ---exit---\n",getpid());
}//./cli 192.168.0.130 50000 
int main(int argc, char const *argv[])
{if (argc != 3){printf("Usage: %s <ip> <port>\n",argv[0]); return -1;       }int clifd = tcp_client_connect(argv[1],argv[2]);if (clifd < 0){printf("tcp_client_connect fail\n");return -1;}// 注冊信號處理函數signal(SIGUSR1,do_handler);pid_t pid = fork();if (pid < 0){perror("fork fail");return -1;}// 注冊退出清理函數if (atexit(cleanup) != 0){perror("atexit fail");return -1;}char buf[1024];if (pid > 0){printf("---f -- pid = %d\n",getpid());while (1){printf(">");fgets(buf,sizeof(buf),stdin);write(clifd,buf,strlen(buf)+1);if (strncmp(buf,"quit",4) == 0){kill(pid,SIGKILL);wait(NULL);exit(0);}}}else if (pid == 0){printf("---c -- pid = %d\n",getpid());while (1){read(clifd,buf,sizeof(buf));if (strncmp(buf,"quit",4) == 0){//kill(getppid(),SIGKILL);kill(getppid(),SIGUSR1); // 使用SIGUSR1信號通知父進程退出exit(0);}printf("cli buf: %s\n",buf);}}// 程序不會執行到這里,但為了完整性保留close(clifd);return 0;
}

sever.c

#include "head.h"int res_fd[2];int tcp_accept(char const*ip,char const * port )
{//step1 socket int fd = socket(AF_INET,SOCK_STREAM,0);if (fd < 0){perror("socket fail");return -1;}res_fd[0] = fd;printf("fd = %d\n",fd);struct sockaddr_in seraddr;//ip 192.168.0.150//port 50000bzero(&seraddr,sizeof(seraddr));seraddr.sin_family = AF_INET;seraddr.sin_port = htons(atoi(port));seraddr.sin_addr.s_addr = inet_addr(ip);if (bind(fd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){perror("connect fail");return -1;}if (listen(fd,5) < 0){perror("listen fail");return -1;}int connfd = accept(fd,NULL,NULL);if (connfd < 0){perror("accept fail");return -1;}res_fd[1] = connfd;return connfd;
}void do_handler(int signo)
{exit(0);
}void cleanup(void)
{close(res_fd[0]);close(res_fd[1]);printf("pid = %d ---cleanup ---exit---\n",getpid());
}int main(int argc, char const *argv[])
{if (argc != 3){printf("Usage: %s <ip> <port>\n",argv[0]);return -1;}int connfd = tcp_accept(argv[1],argv[2]);if (connfd < 0){printf("tcp_accept fail");return -1;}signal(SIGUSR1,do_handler);pid_t pid = fork();if (pid < 0){perror("fork fail");return -1;}//退出資源的管理 if (atexit(cleanup) != 0) // 注冊 一個 清理函數 {perror("atexit fail");return -1;}char buf[1024];if (pid > 0){printf("---f -- pid = %d\n",getpid());while (1){printf(">");fgets(buf,sizeof(buf),stdin);write(connfd,buf,strlen(buf)+1);if (strncmp(buf,"quit",4) == 0){kill(pid,SIGKILL);wait(NULL);exit(0);}}}else if (pid == 0){printf("---c -- pid = %d\n",getpid());while (1){read(connfd,buf,sizeof(buf));if (strncmp(buf,"quit",4) == 0){//kill(getppid(),SIGKILL);kill(getppid(),SIGUSR1);exit(0);}printf("cli buf: %s\n",buf);}}close(connfd);return 0;
}

1. 什么是粘包?

粘包(TCP 粘包問題)是指 發送方 分多次發送的數據包,在 接收方 接收到時,數據會被“粘”在一起,導致接收方無法正確區分數據包的邊界。

2. 粘包的原因

粘包問題本質上是因為 TCP 是面向流的協議,它沒有明確的消息邊界。具體原因如下:

1. TCP 是流式協議

  • TCP 協議把數據看作是一條字節流,不關心應用層的數據是否被完整地發送或接收,接收方只能收到一個“字節流”。

  • 所以,發送方分多次發送的數據可能會被合并在一起發送,也可能是一次發送的數據被拆分成多個小塊接收。

2. 操作系統的緩沖機制

  • TCP 發送方的數據會存入發送緩沖區,直到緩沖區數據達到一定量或操作系統覺得合適時,數據才會被發送出去。

  • 同樣,接收方的操作系統會將收到的網絡數據包緩存到接收緩沖區,等待應用程序讀取。

3. 粘包與拆包

除了粘包,另一個常見的問題是 拆包。拆包是指應用程序發送的數據包在傳輸過程中被拆成多個小包,導致接收方無法正確地拼接成原本的消息。

4. 解決粘包問題

為了避免粘包和拆包的問題,應用層需要通過某種機制來明確 數據包的邊界。常見的解決方法有以下幾種:

1. 固定長度的消息
  • 每個發送的消息都固定長度。接收方一接收到數據,就知道消息的長度。

  • 例如,假設我們每次發送 10 字節 的消息,接收方就可以按照 10 字節 來讀取數據,保證數據不被粘連。

缺點:如果數據量小于固定長度,可能會浪費空間;如果數據量大于固定長度,則需要分段處理。

2. 包頭加包體方式
  • 通過在每個消息前加一個 固定長度的頭部,頭部指定消息的 長度。接收方根據頭部的長度信息來確定如何讀取數據。

  • 例如,發送一個消息時,先發送一個 4 字節的包頭,告訴接收方后續數據的長度。

優點:通過包頭可以解決粘包問題,靈活性高。
缺點:需要處理包頭和包體的分離。

3. 特定的分隔符
  • 采用特定的分隔符(例如 \n## 等)來標識消息的邊界。接收方根據分隔符來區分不同的數據包。

優點:實現簡單,適用于文本數據。
缺點:對于二進制數據不太適用,容易導致數據誤解析。

4. 使用高級協議
  • 一些協議(如 HTTPWebSocketMQTT)已經為數據包邊界做了設計,使用這些協議時,粘包問題會被協議本身解決。

練習:

client.c

#include "../head.h"int tcp_client_connect(char const *ip,char const * port)
{int fd = socket(AF_INET,SOCK_STREAM,0);if (fd < 0){perror("socket fail");return -1;}//printf("fd = %d\n",fd);struct sockaddr_in seraddr;//ip 192.168.0.150//port 50000seraddr.sin_family = AF_INET;seraddr.sin_port = htons(atoi(port)); //atoiseraddr.sin_addr.s_addr = inet_addr(ip);if ( connect(fd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){perror("connect fail");return -1;}return fd;
}//./cli 192.168.0.130 50000 
int main(int argc, char const *argv[])
{if (argc != 3){printf("Usage: %s <ip> <port>\n",argv[0]); return -1;       }int clifd = tcp_client_connect(argv[1],argv[2]);if (clifd < 0){printf("tcp_client_connect fail\n");return -1;}msg_t msg;printf("Input file name:");msg.type = -1;fgets(msg.buf,sizeof(msg.buf),stdin);msg.buf[strlen(msg.buf)-1] = '\0';write(clifd,&msg,sizeof(msg));int fd_s = open(msg.buf,O_RDONLY);if (fd_s < 0){perror("open fail");return -1;}while (1){int ret = read(fd_s,msg.buf,sizeof(msg.buf));msg.type = ret;write(clifd,&msg,sizeof(msg));if (ret == 0)break;}close(fd_s);close(clifd);return 0;
}

server.c

#include "../head.h"int tcp_accept(char const*ip,char const * port )
{//step1 socket int fd = socket(AF_INET,SOCK_STREAM,0);if (fd < 0){perror("socket fail");return -1;}printf("fd = %d\n",fd);struct sockaddr_in seraddr;//ip 192.168.0.150//port 50000bzero(&seraddr,sizeof(seraddr));seraddr.sin_family = AF_INET;seraddr.sin_port = htons(atoi(port));seraddr.sin_addr.s_addr = inet_addr(ip);if (bind(fd,(const struct sockaddr *)&seraddr,sizeof(seraddr)) < 0){perror("connect fail");return -1;}if (listen(fd,5) < 0){perror("listen fail");return -1;}int connfd = accept(fd,NULL,NULL);if (connfd < 0){perror("accept fail");return -1;}return connfd;
}int main(int argc, char const *argv[])
{if (argc != 3){printf("Usage: %s <ip> <port>\n",argv[0]);return -1;}int connfd = tcp_accept(argv[1],argv[2]);if (connfd < 0){printf("tcp_accept fail");return -1;}msg_t msg;read(connfd,&msg,sizeof(msg));printf("buf = %s\n",msg.buf);int fd_d = open(msg.buf,O_WRONLY|O_TRUNC|O_CREAT,0666);if (fd_d < 0){perror("open fail");return -1;}while (1){int ret = read(connfd,&msg,sizeof(msg));if (msg.type == 0)break;write(fd_d,msg.buf,msg.type);}close(connfd);close(fd_d);return 0;
}

recv

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

參數說明

  1. sockfd

    • 要接收數據的套接字描述符。它是通過 socket() 創建,并且已經通過 connect()accept() 建立連接的套接字。

  2. buf

    • 用于接收數據的緩沖區(指針)。接收到的數據會存放在這個緩沖區中。

  3. len

    • 緩沖區的大小,即最多接收的字節數。

  4. flags

    • 控制選項,一般使用 0,表示沒有特殊的控制。也可以使用一些標志,例如:

      • MSG_PEEK:查看數據但不從緩沖區移除。

      • MSG_DONTWAIT:非阻塞模式下調用。

返回值

  • 成功:返回實際接收到的字節數。

    • 如果返回 0,表示對方已經關閉連接。

    • 如果返回大于 0,表示接收到的數據的字節數。

  • 失敗:返回 -1,并設置 errno。常見錯誤包括:

    • EAGAIN / EWOULDBLOCK:非阻塞模式下,接收緩沖區沒有數據。

    • ECONNRESET:連接被對方重置。

recv()read() 的區別

在 Linux 中,recv()read() 函數在套接字上基本上是等價的,都會從套接字中讀取數據。但是 recv() 提供了一些額外的功能:

  • recv() 可以使用 flags 參數,控制接收操作的行為。

  • recv() 更常用于網絡編程,因為它可以在接收數據時設置額外的標志(比如非阻塞接收、查看數據等)。


send

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

參數說明

  1. sockfd

    • 發送數據的套接字描述符,通常是通過 socket() 創建并且已經連接(使用 connect()accept())的套接字。

  2. buf

    • 發送數據的緩沖區(指向內存的指針)。你希望通過 send() 發送的數據應該存放在這個緩沖區中。

  3. len

    • 要發送的字節數(數據的長度)。len 不能超過緩沖區 buf 的大小。

  4. flags

    • 控制發送行為的標志,通常設置為 0,但也可以設置為一些特定的標志,例如:

      • MSG_DONTWAIT:非阻塞模式,立即返回(如果不能發送數據)。

      • MSG_NOSIGNAL:不觸發 SIGPIPE 信號(通常用在當對方關閉連接時)。

返回值

  • 成功:返回實際發送的字節數(即已寫入套接字的字節數)。這個值可能小于你請求發送的字節數(即發送過程可能被中斷,部分數據發送成功)。你需要處理這種情況,確保數據完全發送。

  • 失敗:返回 -1,并設置 errno。常見的錯誤包括:

    • EAGAIN / EWOULDBLOCK:非阻塞模式下,緩沖區沒有空間或者網絡忙。

    • ECONNRESET:連接被對方重置。

send()write() 的區別

Linux 中,send()write() 在行為上是非常相似的。兩者都可以用于套接字,發送數據時的行為幾乎一致。區別在于:

  • send() 函數支持 flags 參數,可以控制發送行為(例如是否阻塞、是否觸發 SIGPIPE 等)。

  • write() 通常用于文件描述符,不具有像 send() 那樣的靈活控制。

所以,send() 更常用于網絡編程,因為它具有更高的控制靈活性。


udb編程

UDP(User Datagram Protocol,用戶數據報協議) 是一個 無連接 的傳輸層協議,它是 TCP 的一個對立面。與 TCP 不同,UDP 不保證數據的可靠性和順序,它簡單、快速、適用于對速度要求高且能容忍一定丟包的場景。

特點:

  • 無連接:UDP 不需要建立連接,發送數據時不進行握手,發送方直接將數據發送給接收方。

  • 不保證順序:接收方可能會收到亂序的包,也可能丟失一些包。

  • 輕量級:UDP 頭部開銷小,適用于對實時性要求較高的應用(例如視頻、語音等流媒體)。

  • 無重傳機制:如果數據丟失,UDP 不會重傳丟失的部分,應用層需要自行處理丟包。

  • 面向數據報:每次發送的數據都是一個獨立的包,且有明確的邊界。

sendto

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);

參數說明

  1. sockfd

    • 類型int

    • 描述:由 socket() 函數創建的套接字描述符。

    • 用途:該套接字用于指定數據發送的目標套接字。對于 UDP,通常是使用 SOCK_DGRAM 類型的套接字。

  2. buf

    • 類型const void *

    • 描述:一個指向數據緩沖區的指針,這個緩沖區包含了要發送的數據。

    • 用途:將要發送的消息數據存放在 buf 中,可以是任何類型的數據(通常是字符串或二進制數據)。

  3. len

    • 類型size_t

    • 描述:緩沖區中要發送的數據的字節數。

    • 用途:指定從 buf 中發送的字節數。例如,如果 buf 是一個字符串,len 就是字符串的長度。

  4. flags

    • 類型int

    • 描述:控制發送操作的標志位。

    • 用途:通常設為 0,但可以使用特定的標志:

      • MSG_DONTWAIT:非阻塞模式。如果套接字的緩沖區沒有足夠的空間,sendto() 會立即返回,而不是阻塞。

      • MSG_NOSIGNAL:防止發送數據時觸發 SIGPIPE 信號(通常在連接被關閉時)。

  5. dest_addr

    • 類型const struct sockaddr *

    • 描述:指向目標地址的指針。

    • 用途:指定接收數據的目標地址,通常是一個 struct sockaddr_in(IPv4 地址)或者 struct sockaddr_in6(IPv6 地址)結構體。

  6. addrlen

    • 類型socklen_t

    • 描述:目標地址結構體的長度。

    • 用途:指定 dest_addr 的長度,通常使用 sizeof(struct sockaddr_in)sizeof(struct sockaddr_in6) 來獲取。

返回值

  • 成功:返回實際發送的字節數(即 len 字節)。

  • 失敗:返回 -1,并設置 errno。常見的錯誤包括:

    • EAGAIN / EWOULDBLOCK:非阻塞模式下,緩沖區沒有足夠的空間。

    • ENOTCONN:套接字未連接(對于某些協議需要連接)。


recvfrom

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

參數說明

  1. sockfd

    • 類型int

    • 描述:由 socket() 創建的 UDP 套接字描述符。

    • 用途:用于指定接收數據的套接字。

  2. buf

    • 類型void *

    • 描述:接收數據的緩沖區。

    • 用途:存放從 UDP 套接字接收到的數據。這個緩沖區的大小應足夠存放可能接收到的最大數據。

  3. len

    • 類型size_t

    • 描述:緩沖區的大小,即最多接收的字節數。

    • 用途:告知 recvfrom() 函數最多接收多少字節數據。

  4. flags

    • 類型int

    • 描述:接收的控制選項,通常設置為 0,但可以使用一些標志,例如:

      • MSG_PEEK:查看數據但不從接收緩沖區移除數據。

      • MSG_DONTWAIT:非阻塞模式,立即返回(如果沒有數據可接收)。

  5. src_addr

    • 類型struct sockaddr *

    • 描述:指向發送方地址的結構體指針。

    • 用途:接收數據時,會將發送方的地址信息(如 IP 地址和端口)存放在這里。

    • 通常使用 struct sockaddr_in(IPv4)或 struct sockaddr_in6(IPv6)來表示。

  6. addrlen

    • 類型socklen_t *

    • 描述:發送方地址結構體的長度,接收時會更新為實際的地址長度。

    • 用途:傳遞給 recvfrom() 時,表示地址結構的大小,返回時更新為實際接收的數據源地址的長度。

返回值

  • 成功:返回接收到的字節數。如果接收到的數據是完整的消息,recvfrom() 將返回實際接收到的數據字節數。

  • 失敗:返回 -1,并設置 errno。常見錯誤包括:

    • EAGAIN / EWOULDBLOCK:非阻塞模式下,沒有數據可以接收。

    • ECONNRESET:連接被重置。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/919796.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/919796.shtml
英文地址,請注明出處:http://en.pswp.cn/news/919796.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

零知開源——基于STM32F103RBT6與ADXL362三軸加速度計的體感迷宮游戲設計與實現

?零知IDE 是一個真正屬于國人自己的開源軟件平臺&#xff0c;在開發效率上超越了Arduino平臺并且更加容易上手&#xff0c;大大降低了開發難度。零知開源在軟件方面提供了完整的學習教程和豐富示例代碼&#xff0c;讓不懂程序的工程師也能非常輕而易舉的搭建電路來創作產品&am…

《Linux 網絡編程一:網絡編程導論及UDP 服務器的創建與數據接收》

Linux下的網絡編程1. 目的實現不同主機之間進程的通信。2. 問題主機之間在物理層面必須互聯互通。進程之間在軟件層面必須互聯互通。IP地址&#xff1a;計算機的軟件地址&#xff0c;用于標識計算機設備。MAC地址&#xff1a;計算機的硬件地址&#xff08;固定&#xff09;。網…

排序(數據結構)

比較排序 插入排序&#xff08;斗地主摸牌就是一個插入排序&#xff09; 單純的插入排序也叫直接插入排序 時間復雜度&#xff1a; 最好O(n)最壞O(n^2) 過程 先寫單趟&#xff0c;再寫整體 依次比較&#xff0c;如果大于就往后挪動&#xff0c;否則就退出循環&#xff0c;插入數…

【C++組件】Elasticsearch 安裝及使用

&#x1f308; 個人主頁&#xff1a;Zfox_ &#x1f525; 系列專欄&#xff1a;C框架/庫 目錄&#x1f525; 介紹 &#x1f525; ES 安裝 &#x1f98b; 安裝 kibana&#x1f98b; ES 客戶端的安裝&#x1f525; ES 核心概念 &#x1f98b; 索引&#xff08;Index&#xff09;&…

項目:電動車報警器

1.項目需求 點擊遙控器A按鍵&#xff0c;系統進入警戒模式&#xff0c;一旦檢測到震動(小偷偷車)&#xff0c;則喇叭發出聲響報警&#xff0c;嚇退小偷。 點擊遙控器B按鍵&#xff0c;系統退出警戒模式&#xff0c;再怎么搖晃系統都不會報警&#xff0c;否則系統一直發出尖叫&a…

GDSFactory環境配置(PyCharm+Git+KLayout)

1、安裝 PyCharm 和 KLayout 安裝 PyCharm&#xff08;官網社區版即可&#xff09;和 KLayout&#xff08;官網最新版&#xff09;&#xff0c;這兩款軟件均開源&#xff0c;安裝操作簡單&#xff0c;這里不再贅述。&#xff08;注意&#xff1a;PyCharm軟件是否安裝成功以能否…

STM32 定時器(輸出模式)

?? ?一、輸出模式總覽?STM32定時器的輸出比較模式通過比較計數器&#xff08;CNT&#xff09;與捕獲/比較寄存器&#xff08;CCRx&#xff09;的值&#xff0c;控制輸出引腳&#xff08;OCx&#xff09;的電平狀態。六種模式定義如下&#xff1a;?模式宏??觸發動作?&am…

嵌入式硬件篇---手柄

手柄原理&#xff1a;手柄遙控的原理其實可以簡單理解為 “信號的發送與接收”&#xff0c;就像兩個人用對講機聊天&#xff0c;一方說話&#xff08;發送信號&#xff09;&#xff0c;另一方聽話&#xff08;接收信號&#xff09;&#xff0c;然后根據內容行動。下面用通俗的方…

數據庫架構開發知識庫體系

摘要面向初創與企業團隊&#xff0c;系統梳理數據庫與數據平臺從采集、傳輸、存儲、處理、服務化到治理與安全的全鏈路。覆蓋 OLTP/OLAP/HTAP、湖倉一體與實時數據棧&#xff0c;結合國內外工具與方法論&#xff0c;給出架構選型、性能優化、可靠性與合規要點&#xff0c;以及可…

在Excel和WPS表格中合并多個單元格這樣最快

如果要把WPS表格和Excel中多個單元格的數據合成到一個單元格中&#xff0c;不用函數&#xff0c;只需要先寫輸入公式&#xff0c;然后在各個單元格之間輸入&符號即可。&#xff08;當然&#xff0c;&符號不只是連接單元格的數據&#xff0c;也可以直接輸入內容連接&…

在嵌入式上用 C++14實現簡單HSM狀態機

文章目錄概述為什么要遷移到 C&#xff0c;以及 C 的陷阱目標與挑戰為什么不能直接使用 std::function&#xff1f;解決方案&#xff1a;POD 回調與模板 Trampoline核心設計模板 trampoline 實現兩種成員函數綁定策略1. **Per-Transition Context&#xff08;每個狀態轉移綁定一…

【unity】Obfuz加固混淆日志還原解析方案ObfuzResolver

Github | Gitee ObfuzResolver是基于obfuz-tools針對Obfuz的一項輔助工具&#xff0c;方便開發者在unity編輯器中或者運行時快捷將使用Obfuz混淆加固后的日志信息還原為原始信息&#xff0c;以輔助開發者快速定位Bug。 特性 支持unity編輯器模式下還原被加固混淆的日志信息&a…

2025DevOps平臺趨勢解讀:哪些DevOps工具正在引領行業變革?

DevOps平臺已成為企業提升研發效能、實現敏捷交付的核心支柱。2025年DevOps領域正經歷深刻變革&#xff0c;平臺能力正從“工具鏈整合”向“價值流智能中樞”躍升。01. 2025Devops平臺趨勢解讀“全棧式”與“模塊化/可組合”的平衡&#xff1a;企業既需要能覆蓋開發、測試、部署…

第二階段Winform-4:MDI窗口,布局控件,分頁

1_MDI窗口 &#xff08;1&#xff09;MDI是指將多控件窗體在同一窗體中打開,可以設置重疊打開&#xff0c;平捕打開等&#xff0c;MDI窗體&#xff08;Multiple-Document Interface&#xff0c;多文檔界面&#xff09;用于同時顯示多個文檔。在項目中使用MDI窗體時&#xff0c…

實用R語言機器學習指南:從數據預處理到模型實戰(附配套學習資源)

一、為什么需要掌握機器學習建模&#xff1f;在科研與項目實踐中&#xff0c;機器學習已成為數據挖掘的核心工具。本文手把手帶你在R語言中實現7大常用模型&#xff1a;邏輯回歸/正則化回歸決策樹/隨機森林SVM支持向量機XGBoost梯度提升神經網絡全程包含數據標準化→模型訓練→…

go.uber.org/zap 日志庫高性能寫入

使用 go.uber.org/zap 實現日志分割功能 實現按照單個文件最大MB自動分割,最多保留多少天的文件,是否啟用壓縮,按天自動分割日志 核心依賴 go.uber.org/zap:核心日志庫 lumberjack.v2:日志輪轉工具(實現按大小/時間分割) 時間處理依賴標準庫 time 實現步驟 1. 初始化…

電腦端完全免費的動態壁紙和屏保軟件(真正免費、無廣告、無會員)

? 1. Lively Wallpaper&#xff08;強烈推薦&#xff09; 特點&#xff1a;完全免費、開源、無廣告&#xff0c;支持本地視頻/GIF/網頁作為動態壁紙內置資源&#xff1a;12個高質量動態壁紙&#xff08;可自定義&#xff09;屏保功能&#xff1a;支持將動態壁紙一鍵設為屏保系…

C#_組合優于繼承的實際應用

2.2 Composition over Inheritance&#xff1a;組合優于繼承的實際應用 繼承&#xff08;Inheritance&#xff09;是面向對象編程中最容易被過度使用和誤用的特性之一。傳統的教學往往讓人們優先選擇繼承來實現代碼復用和建立“是一個&#xff08;is-a&#xff09;”的關系。然…

Kafka消息丟失的場景有哪些

生產者在生產過程中的消息丟失 broker在故障后的消息丟失 消費者在消費過程中的消息丟失ACK機制 ack有3個可選值&#xff0c;分別是1&#xff0c;0&#xff0c;-1。 ack0&#xff1a;生產者在生產過程中的消息丟失 簡單來說就是&#xff0c;producer發送一次就不再發送了&#…

盼之代售 231滑塊 csessionid 分析

聲明 本文章中所有內容僅供學習交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包內容、敏感網址、數據接口等均已做脫敏處理&#xff0c;嚴禁用于商業用途和非法用途&#xff0c;否則由此產生的一切后果均與作者無關&#xff01; 逆向分析 部分python代碼 url "…