【Linux開發實戰指南】基于TCP、進程數據結構與SQL數據庫:構建在線云詞典系統(含注冊、登錄、查詢、歷史記錄管理功能及源碼分享)

目錄

?項目演示:

1. 主界面

技術講解:

TCP連接

進程的并發

鏈表

SQLite3

IO對文件的讀寫

功能實現

實現邏輯

我遇到的問題:

服務器端代碼思路解析

必要條件

步驟詳解

客戶端代碼思路解析

步驟詳解

服務器源碼如下:

?客戶端源碼如下:

dictionary.h源碼如下:

dic.txt文件因為過于龐大,所以放到公眾號中,大家需要自取。


?項目演示:

1. 主界面

2. 注冊

3. 登錄

4. 查詢單詞

5. 查詢歷史記錄

6. 刪除歷史記錄

7. 退出

技術講解:

TCP連接

TCP(Transmission Control Protocol)連接是互聯網上最常用的一種面向連接、可靠的、基于字節流的傳輸層通信協議。建立TCP連接需要經過著名的“三次握手”過程:

  1. SYN(同步序列編號):客戶端發送一個SYN包給服務器,并進入SYN_SEND狀態,等待服務器確認。
  2. SYN-ACK:服務器收到SYN包后,回應一個SYN-ACK(SYN+ACKnowledgment)包,告訴客戶端其接收到了請求,并同意建立連接,此時服務器進入SYN_RECV狀態。
  3. ACK(確認字符):客戶端收到服務器的SYN-ACK包后,發送一個ACK包給服務器,確認收到了服務器的確認信息。此時,TCP連接正式建立,雙方進入ESTABLISHED狀態。

進程的并發

進程并發是指多個進程在同一時間段內交替執行的現象,操作系統通過時間片輪轉、優先級調度等策略來管理進程的執行,給予每個進程一定的CPU時間來執行任務,從而實現“同時”處理多個任務的效果。并發可以提高系統資源利用率和整體處理能力,但也會帶來資源競爭、死鎖等問題,需要通過同步機制(如互斥鎖、信號量等)來協調。

鏈表

鏈表是一種重要的數據結構,用于存儲線性集合的元素,每個元素(節點)包含數據和指向下一個節點的指針。鏈表分為單鏈表、雙鏈表、循環鏈表等類型。與數組相比,鏈表的優點在于插入和刪除操作更快,因為它不需要移動其他元素,只需修改相鄰節點的指針。缺點是訪問元素不如數組直接,需要從頭節點開始逐個遍歷。

SQLite3

SQLite3是一個輕量級、無服務器、零配置的嵌入式數據庫引擎,它允許程序將整個數據庫(包括定義、表、索引和數據)存儲在單一的文件中。SQLite支持SQL語言,可以用于各種應用開發,特別是在那些需要本地存儲、對數據庫服務器要求不高或不想管理數據庫服務器的場景下,如手機應用、桌面應用等。SQLite的特點是易于集成、跨平臺、占用資源少。

IO對文件的讀寫

在編程中,對文件的讀寫是基礎的IO操作,主要通過系統調用或庫函數實現。以C語言為例:

  • 讀文件:通常使用fopen函數打開文件,然后通過freadfgets等函數讀取內容。例如:

    C
    1FILE *file = fopen("example.txt", "r");
    2if (file != NULL) {
    3    char buffer[255];
    4    fgets(buffer, sizeof(buffer), file);
    5    fclose(file);
    6}
  • 寫文件:同樣使用fopen函數以寫模式打開文件,然后通過fwritefprintf等函數寫入數據。例如:

    C
    1FILE *file = fopen("output.txt", "w");
    2if (file != NULL) {
    3    fprintf(file, "Hello, World!\n");
    4    fclose(file);
    5}

這些操作涉及文件句柄、緩沖區管理及錯誤處理,是進行文件操作的基本步驟。

功能實現
  1. Linux系統編程:利用Linux環境下的高級編程技巧。
  2. 用戶的注冊和登錄:實現安全的用戶認證機制。
  3. 查詢單詞:高效檢索詞典數據庫中的詞匯信息。
  4. 查詢或刪除歷史記錄:提供用戶對過往查詢記錄的操作功能。
實現邏輯

本節將詳細介紹開發過程的關鍵步驟,幫助你從零開始構建這一系統。

  1. 創建SQLite3數據庫:用于存儲用戶賬戶信息及查詢歷史記錄,確保數據的持久化和安全性。

    • 設計數據庫模式,包括用戶表和歷史記錄表。
    • 實現增刪查改的基本操作。
  2. 定義請求類型:通過結構體區分注冊、登錄、查詢單詞和管理歷史記錄等不同操作。

    • 結構體設計應包含所有必要的字段,如用戶名、密碼、操作類型等。
    • 利用鏈表存儲結構體實例,便于動態管理。
  3. 搭建代碼框架:先構建整體框架,再逐步填充細節。

    • 定義服務器和客戶端的主循環。
    • 規劃函數調用流程,預留函數體以便后續填充。
  4. 確保TCP通信穩定:實現可靠的雙向數據傳輸。

    • 初始化TCP套接字,監聽端口。
    • 處理連接請求,接收和發送數據包。
    • 驗證數據格式,防止解析錯誤。
  5. 準備單詞文檔:作為詞典數據源。

    • 選擇合適的單詞列表文件。
    • 使用標準I/O庫讀取和解析文檔。
  6. 實現核心邏輯:編寫關鍵算法和業務處理代碼。

    • 注冊和登錄驗證:檢查用戶信息的正確性。
    • 單詞查詢:采用高效的數據結構加速檢索。
      • 注意:使用回調函數時,確保條件判斷準確無誤,避免查詢失敗或結果不匹配。
    • 歷史記錄管理:記錄和展示用戶的查詢歷史,提供刪除選項。

我遇到的問題:

大概思路圖:

服務器端代碼思路解析

必要條件
  • 并發能力:采用進程并發模型,確保服務器能同時處理來自多個客戶端的請求。
  • 通信方式:基于TCP協議,實現可靠的數據傳輸。
步驟詳解
  1. 創建數據庫表

    • 設計兩個SQLite3表:一個用于存儲用戶賬號信息(用戶名、密碼),另一個用于記錄歷史查詢數據。
    • 實現基本的CRUD(創建、讀取、更新、刪除)操作,確保數據的準確性和完整性。
  2. 初始化網絡服務

    • 創建TCP套接字,設置相關屬性。
    • 綁定IP地址和端口號,啟動監聽,準備接受客戶端連接。
    • 接收客戶端連接請求,為每個連接創建新進程以處理并發請求。
  3. 處理客戶端請求

    • 讀取客戶端發送的完整結構體數據包。
    • 使用switch語句分析請求類型,調用相應的處理函數。
      • 注冊/登錄:驗證用戶信息,更新數據庫狀態。
      • 查詢單詞:搜索詞典數據庫,返回查詢結果。
      • 歷史記錄:記錄或檢索用戶的歷史查詢記錄。

客戶端代碼思路解析

步驟詳解
  1. 初始化網絡連接

    • 創建TCP套接字,指定服務器地址和端口。
    • 連接到服務器,建立通信通道。
    • 準備發送和接收數據。
  2. 交互邏輯

    • 打印幫助菜單,指導用戶輸入命令。
    • 根據用戶輸入,調用相應函數處理請求。
      • 注冊/登錄:向服務器發送用戶信息,等待認證結果。
      • 查詢單詞:提交單詞查詢請求,接收查詢結果。
      • 歷史記錄:請求歷史記錄,顯示或刪除記錄。

服務器源碼如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "dictionary.h"
#include <sqlite3.h>
#include <signal.h>
#include <sys/wait.h>
#include <time.h>int acceptfd;
int search_word(int acceptfd);
int num = 10;
time_t t;
struct tm *tm;
// 注冊函數
void register_sev(int acceptfd, char *p, sqlite3 *db)
{char sql[128] = " "; //定義數組來裝insert語句sprintf(sql, "insert into user values('%s','%s');", dic.name, dic.password);//如果插入不成功則給dic.text賦值失敗反之OKif (sqlite3_exec(db, sql, NULL, NULL, &p) != SQLITE_OK){strcpy(dic.text, "already exits!");}else{strcpy(dic.text, "OK");}send(acceptfd, &dic, sizeof(dic), 0); //發送
}// 登錄函數
void login_sev(int acceptfd, char *p, char **result, int row, int line, sqlite3 *db)
{// 定義一個輸入去接收這個查詢用戶名和密碼的語句char buf[128];sprintf(buf, "select * from user where name = '%s' and password = '%s';", dic.name, dic.password);// 先把輸入的數據查詢一下在表里,如果表里有數據則代表數據庫有密碼if (sqlite3_get_table(db, buf, &result, &row, &line, &p) != SQLITE_OK){perror("sev sqlite3_table error\n");return;}// 如果行大于零則代表有數據成功if (row > 0){strcpy(dic.text, "login successs");}else{strcpy(dic.text, "login loose,please check your name or password!");}send(acceptfd, &dic, sizeof(dic), 0);
}// 查詢單詞
void query_sev(int acceptfd, sqlite3 *db, char *p)
{time_t t;struct tm *tm;int a = 0;//定義一個語句去接受查詢的語句char sql2[128] = "";int found = search_word(acceptfd); //去接受查詢單詞這個函數的返回值 不為1則代表失敗 返回1則代表成功if (found != 1){strcpy(dic.text, "can't find \n");send(acceptfd, &dic, sizeof(dic), 0);}else{time(&t);tm = localtime(&t);sprintf(dic.time_sev, "%d-%d-%d %d:%d:%d", tm->tm_year + 1900,tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);sprintf(sql2, "insert into record values('%s','%s');", dic.password, dic.time_sev); // 成功后就把查詢成功的單詞插入到record這個表里if (sqlite3_exec(db, sql2, NULL, NULL, &p) != SQLITE_OK){perror("record insert error\n");return;}}
}// 查詢單詞函數
int search_word(int acceptfd)
{//定義每次接受來的密碼的長度int len = strlen(dic.password);//打開文件用標準IOFILE *sp = fopen("dic.txt", "r");if (NULL == sp){perror("sp error\n");return -1;}//如果dic.txt文件不為空時繼續執行while (fgets(dic.text, sizeof(dic.text), sp) != NULL){//拿密碼去比較文件中的前幾位 如果成功發送dic 并且返回1if (!strncmp(dic.text, dic.password, len)){send(acceptfd, &dic, sizeof(dic), 0);return 1;}}
}//回調函數
int history_callback(void *arg, int colunms, char **text, char **name)
{if (text != NULL){sprintf(dic.text, "%s %s", text[0], text[1]);send(acceptfd, &dic, sizeof(dic), 0);}return 0;
}//歷史函數
int history_sev(char *p, sqlite3 *db)
{if (sqlite3_exec(db, "select * from record;", history_callback, NULL, &p) != SQLITE_OK) // 此處用的是回調函數{fprintf(stderr, "select is error: %s\n", p); //如果不等于OK責代表沒成功,報錯return -1;}elseprintf("請求成功\n");dic.history_id = 1;send(acceptfd, &dic, sizeof(dic), 0);return 0;
}void delete_history(char *p, sqlite3 *db)
{if (sqlite3_exec(db, "delete from record;", NULL, NULL, &p) != SQLITE_OK){fprintf(stderr, "delete is error: %s\n", p); //如果不等于OK責代表沒成功,報錯}else{strcpy(dic.text, "刪除成功!");send(acceptfd, &dic, sizeof(dic), 0);}
}//處理僵尸進程
void hanlder(int arg)
{waitpid(-1, NULL, WNOHANG);
}int main(int argc, char const *argv[])
{//1. 創建sql表sqlite3 *db = NULL;if (sqlite3_open("./dictionary.db", &db) != 0){fprintf(stderr, "sqlite3 is error%s\n", sqlite3_errmsg(db));return -1;}// 創建兩個表char *p = NULL;if (sqlite3_exec(db, "create table user(name char primary key, password char);", NULL, NULL, &p) != SQLITE_OK){fprintf(stderr, "create stu1 is error %s\n", p);return -1;}if (sqlite3_exec(db, "create table record(password char,time char);", NULL, NULL, &p) != SQLITE_OK){fprintf(stderr, "create record is error %s\n", p);return -1;}// 創建指針以及行和列的變量char **result = NULL;int row = 0;int line = 0;// 創建套接字int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("sev sockfd error\n");return -1;}//填充結構體struct sockaddr_in saddr, caddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(atoi(argv[1]));saddr.sin_addr.s_addr = inet_addr("0.0.0.0");int len = sizeof(caddr);// 綁定 和 監聽if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){perror("bind error\n");return -1;}if (listen(sockfd, 5) < 0){perror("sev listen error\n");return -1;}// 處理僵尸進程signal(SIGCHLD, hanlder);// 循環去接受while (1){acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);if (acceptfd < 0){perror("sev acceptfd is error\n");return -1;}// 創建進程pid_t pid = fork();if (pid < 0){perror("sev pid error\n");return -1;}else if (pid == 0) // 子進程{while (recv(acceptfd, &dic, sizeof(dic), 0)){switch (dic.type){case 'r':register_sev(acceptfd, p, db); // 注冊函數break;case 'l':login_sev(acceptfd, p, result, row, line, db); // 登錄函數break;case 'q':query_sev(acceptfd, db, p); //查詢函數break;case 'h':history_sev(p, db); //歷史查詢函數break;case 'd':delete_history(p, db);// 歷史記錄刪除函數break;default:break;}}}else // 父進程{close(acceptfd);}}return 0;
}

?客戶端源碼如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "dictionary.h"
#include <sqlite3.h>
// 聲明函數
void query(int sockfd);
void History(int sockfd);
void delete_history(int sockfd);
//注冊
void register_sev(int sockfd)
{printf("*******注冊頁面*******\n");dic.type = 'r'; // 令他的類型等于r 也就是我設置的注冊類型printf("請輸入你的用戶名: ");scanf("%s", dic.name);printf("請輸入你的密碼: ");scanf("%s", dic.password);send(sockfd, &dic, sizeof(dic), 0);int recvfd = recv(sockfd, &dic, sizeof(dic), 0);if (recvfd < 0)// 接受失敗{perror("recv error\n");return;}else if (recvfd == 0)// 服務器退出{printf("Sever already quit\n");return;}else // 接受成功{printf("%s\n", dic.text);}
}
//登錄
int login_sev(int sockfd)
{printf("*******登錄頁面*******\n");dic.type = 'l';printf("請輸入你的用戶名: ");scanf("%s", dic.name);getchar();printf("請輸入你的密碼: ");scanf("%s", dic.password);getchar();send(sockfd, &dic, sizeof(dic), 0);//將整個結構體發送過去//接受整個結構體 如果接受錯誤的話就返回-1如果 登錄成功就返回1int recvfd = recv(sockfd, &dic, sizeof(dic), 0);if (recvfd < 0){perror("recv error\n");return -1;}else if (recvfd == 0){printf("Sever already quit\n");return -1;}else{if (!strcmp(dic.text, "login successs")) // 如果接收到客戶端發過來的成功語句就打印成功{printf("登錄成功!\n");return 1;}else{printf("%s\n", dic.text);}}
}
// 進入登錄后的頁面
void next(int sockfd)
{int next;while (1){printf("*****************************查詢頁面***********************************\n");
printf("1.: query_password     2.: History_password   3:delete:History  4.:quit\n");      printf("***********************************************************************\n");printf("\n");printf("Please choose:");scanf("%d", &next);switch (next){case 1:query(sockfd); //查詢函數break;case 2:History(sockfd); //歷史函數break;case 3:delete_history(sockfd); // 刪除歷史記錄break;case 4:close(sockfd); //返回上一級exit(0);default:break;}}
}
// 查詢單詞
void query(int sockfd)
{dic.type = 'q';while (1){printf("Please input words that you want to search: ");scanf("%s", dic.password);putchar(10);                    //防止垃圾字符if (!strcmp(dic.password, "#")) //如果在查找單詞中輸入#就會退出{break;}send(sockfd, &dic, sizeof(dic), 0); // 將結構體發過去int recvfd = recv(sockfd, &dic, sizeof(dic), 0);if (recvfd < 0){perror("recv error\n");return;}else if (recvfd == 0){printf("Sever already quit\n");return;}else{printf("%s this word is expain: %s", dic.password, dic.text);printf("\n");}}
}
// 歷史記錄
void History(int sockfd)
{dic.type = 'h';send(sockfd, &dic, sizeof(dic), 0); // 目的是為了將結構體類型發過去while (1){int recvfd = recv(sockfd, &dic, sizeof(dic), 0);if (recvfd < 0){perror("recv error\n");return;}if(dic.history_id == 1)break;printf("%s\n",dic.text);printf("\n");}
}
// 刪除歷史記錄
void delete_history(int sockfd)
{dic.type = 'd';send(sockfd, &dic, sizeof(dic), 0); // 目的是為了將結構體類型發過去while (1){int recvfd = recv(sockfd, &dic, sizeof(dic), 0);if (recvfd < 0){perror("recv error\n");return;}else if (recvfd == 0){exit(0);}else{printf("%s \n", dic.text);printf("\n");break;}}
}int main(int argc, char const *argv[])
{//1. 創建套接字int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("cli sockfd error\n");return -1;}//2.填充結構體struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(atoi(argv[2]));saddr.sin_addr.s_addr = inet_addr(argv[1]);//鏈接if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){perror("cli connect erroen\n");return -1;}int cli_type1;while (1){printf("**************************************\n");printf("1: register     2: login     3:quit\n");printf("**************************************\n");printf("Please choose (must number!!!):");scanf("%d", &cli_type1);if (cli_type1 != 1 && cli_type1 != 2 && cli_type1 != 3){printf("請重新輸入正確的數字!\n");return -1;}switch (cli_type1){//2.注冊case 1:register_sev(sockfd);break;//3.登錄case 2:if (login_sev(sockfd) == 1) //接受上面返回成功的1進行到下一個函數next(sockfd);break;//4.退出case 3:close(sockfd);exit(0);default:break;}}return 0;
}

dictionary.h源碼如下:

struct dictionary
{char type; // r代表注冊 l 代表登錄 q代表查詢 h代表歷史char name[128];// 用戶名char password[128];// 密碼char text[128];// 通知內容或者查找內容char time_sev[32];// 時間int history_id;
} dic;

dic.txt文件因為過于龐大,所以放到公眾號中,大家需要自取。

微信關注嵌入式工程之家發送? ?dic源碼? 即可獲得文件喲。

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

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

相關文章

windows電腦如何運行python的定時任務

這里需要使用&#xff1a;windows系統設置-控制面板里的計劃任務 1.打開計劃任務之后&#xff0c;選擇&#xff1a;創建基本任務 2.填寫名稱&#xff0c;這里根據自己具體的項目需求填寫&#xff0c;然后點擊下一步。 3.選擇每日&#xff0c;再點擊下一步 4.設置時間&…

Python 學習之常用第三方庫(五)

Python 常用第三方庫 Python 是一門功能強大的編程語言&#xff0c;其生態系統中包含了許多優秀的第三方庫&#xff0c;這些庫極大地擴展了 Python 的功能。以下是一些常用的 Python 第三方庫&#xff1a; 1. NumPy&#xff1a; a. 用于數值計算的庫&#xff0c;提供了大量的…

科普文:linux I/O原理、監控、和調優思路

Linux 文件系統 磁盤和文件系統的關系&#xff1a; 磁盤為系統提供了最基本的持久化存儲。 文件系統則在磁盤的基礎上&#xff0c;提供了一個用來管理文件的樹狀結構。 文件系統工作原理 索引節點和目錄項 文件系統&#xff0c;本身是對存儲設備上的文件&#xff0c;進行…

多維度多場景文檔門戶,鴻翼ECM文檔云打造文檔管理新范式

?在現代企業運營中&#xff0c;內容協作的效率直接影響到組織的整體表現和競爭力。傳統的文檔管理系統都是通過目錄結構的方式進行文件管理&#xff0c;在實際業務中無法滿足用戶多視角、多維度、多場景的文檔業務需求。因此&#xff0c;搭建結合文檔體系的業務門戶是許多企業…

策略模式入門:基本概念與應用

目錄 策略模式策略模式結構策略模式應用場景策略模式優缺點練手題目題目描述輸入描述輸出描述題解 策略模式 策略模式&#xff0c;又稱政策模式&#xff0c;是一種行為型設計模式&#xff0c;它能讓你定義一系列算法&#xff0c;并將每種算法分別放入獨立的類中&#xff0c;以…

數字研發·驅動變革 | 2024達索系統裝備行業數字化研發專題研討會成功舉辦

2024年6月28日&#xff0c;由百世慧舉辦的“數字研發驅動變革|2024達索系統裝備行業數字化研發專題研討會”在達索系統&#xff08;重慶&#xff09;智能制造創新中心成功舉辦。 隨著全球制造業向著智能化、數字化轉型&#xff0c;我國工業裝備行業也面臨著轉型升級的壓力和機遇…

Gym cuda error: invalid resource handle

gym模擬的時候&#xff0c; 出現問題&#xff1a; sim和gym的定義如下&#xff1a; from isaacgym import gymapi,gymtorch import math,random# 1. Simulation Setup gym gymapi.acquire_gym()# get default set of parameters sim_params gymapi.SimParams() sim_params.u…

網關,路由器,交換機

一、網關 (Gateway) 是一種設備&#xff0c;用于連接不同網絡&#xff0c;能夠轉發數據包并翻譯協議&#xff0c;允許不同類型的網絡通信。網關通常工作在OSI模型的應用層或傳輸層&#xff0c;提供連接和路由服務。 應用場景例子&#xff1a; 在企業網絡中&#xff0c;網關可…

四倍體和六倍體小麥抗赤霉病的比較研究

核心總結&#xff1a;四倍體和六倍體小麥抗赤霉病的比較研究 研究背景 小麥赤霉病&#xff08;Fusarium head blight, FHB&#xff09;由Fusarium graminearum引起&#xff0c;是全球范圍內對小麥生產造成嚴重威脅的疾病。FHB感染不僅會顯著降低糧食產量和質量&#xff0c;還…

2024年能在一個月內錄用的EI檢索會議CCPQT 2024

第三屆計算、通信、感知與量子技術國際會議&#xff08;CCPQT 2024&#xff09;將于2024 年10月25日-10月27日在中國珠海召開。&#xff08;往屆均已順利見刊檢索&#xff09; 會議信息 大會官網&#xff1a;http://www.ccpqt.org/ 會議地點&#xff1a;中國珠海 會議時間&…

企業多存儲方式如何兼顧安全統一管理、便捷流暢訪問的雙向需求?

數據和文件存儲是企業最基礎的需求&#xff0c;常見的存儲方式有磁盤存儲、NAS存儲、SAN存儲、云存儲、分布式存儲、閃存存儲等&#xff1b;隨著企業規模的擴大、業務結構的復雜化&#xff0c;企業內部可能會同時出現多種存儲方式、多個存儲設備并行使用的情況。 這樣的使用場景…

python之音頻處理(1)語速快慢的改變

方案1&#xff1a;使用pydub 處理 from pydub import AudioSegment sound AudioSegment.from_file(r"D:\websiteDownload\我今天被一件事情搞得很煩.wav") print(sound.duration_seconds) rate 0.75 sound_with_altered_frame_rate sound._spawn(sound.raw_data,…

【啟明智顯技術分享】Model3C芯片電阻屏RTP配置、調試與測試指南

一、背景 本指南將詳細介紹啟明智顯的Model3C芯片電阻屏RTP配置、調試與測試指南。無論您是電子愛好者、開發者還是工程師&#xff0c;這份指南都能助您快速上手并充分利用這款觸摸屏的各項功能。 二、芯片介紹 Model3C是一款基于RISC-V的高性能、國產自主、工業級高清顯示與…

java通過jts獲取點在線段中的位置

在Java中&#xff0c;可以使用JTS&#xff08;Java Topology Suite&#xff09;庫來獲取點在線段的垂足點位置。以下是一個簡單的示例代碼&#xff0c;展示了如何使用JTS獲取點到線段的垂足點位置&#xff1a; 首先&#xff0c;確保你的項目中包含了JTS庫。 import org.locati…

面試篇-系統設計題總結

這里記錄一些有趣的系統設計類的題目&#xff0c;一般大家比較喜歡出的設計類面試題目會和高可用系統相關比如秒殺和搶紅包等。歡迎大家在評論中評論自己遇到的題目&#xff0c;本篇文章會持續更新。 1、設計一個搶紅包系統 搶紅包系統其實也是秒殺類中的一個場景&#xff0…

深度學習中的反向傳播算法的原理

深度學習中的反向傳播算法的原理&#xff0c;以及如何計算梯度 反向傳播算法&#xff08;Backpropagation&#xff09;是深度學習中最核心的優化技術之一&#xff0c;用于訓練神經網絡。它基于鏈式法則&#xff0c;通過從輸出層逆向計算誤差并逐層傳遞到輸入層來更新模型參數&…

類的動態加載-雙親委派模型

java反射基礎 Java 基礎 - 反射機制詳解 | Java 全棧知識體系 (pdai.tech) 類的動態加載 參考鏈接&#xff1a;類的動態加載 構造是和實例化也就是對象相關的。 靜態代碼塊是在初始化的時候就調用的 Class.forName();就會調用靜態代碼塊 forName&#xff0c;加載類時默認…

你們叫AI,我們叫DI

大家好&#xff0c;才是真的好。 最近Notes/Domino產品在做哪些更新&#xff0c;想必大家都很好奇。 從2022年年末到現在&#xff0c;快兩年了&#xff0c;任何一個有追求的大企業或巨頭&#xff0c;應該都在追求實現一件事情&#xff1a;AI人工智能。 從小道消息來看&#…

深度學習之OpenCV的DNN模塊

OpenCV的DNN&#xff08;Deep Neural Network&#xff09;模塊是一個強大的工具&#xff0c;允許開發者在計算機視覺應用中使用深度學習模型。該模塊支持多種深度學習框架和模型格式&#xff0c;并提供了高效的推理能力。以下是對OpenCV DNN模塊的詳細介紹&#xff0c;包括其功…

Unity實現等弧長的曲線滾動列表

Unity實現等弧長的曲線滾動列表 在Unity中實現等弧長的曲線滾動列表通常涉及到曲線路徑生成、物理模擬以及動畫控制。首先&#xff0c;你需要創建一個可滾動的UI元素&#xff08;如List或ScrollView&#xff09;&#xff0c;并將其錨點設置在一個可以跟隨曲線移動的位置。以下…