萬字詳解網絡編程之socket

一,socket簡介

1.什么是socket

socket通常也稱作"套接字",?于描述IP地址和端?,是?個通信鏈的句柄,應用程序通常通過"套接字"向?絡發出請求或者應答?絡請求。?絡通信就是兩個進程間的通信,這兩個進程之間是如何識別彼此的呢?那就是套接字(Socket),每個套接字由?個 IP 地址和?個端?號組成。
Socket起源于Unix,?Unix/Linux基本哲學之?就是“?切皆?件”,對于?件?【打開】【讀寫】【關閉】模式來操作
socket是?種特殊的?件,?些socket函數就是對其進?的操作(打開、讀/寫IO、關閉)。
套接字的類型:
1.流式套接字(SOCK_STREAM)
提供了?個面向連接、可靠的數據傳輸服務,數據?差錯、? ? 重復的發送且按發送順序接收。內設置流量控制,避免數據流 ? 淹沒慢的接收?。數據被看作是字節流,無長度限制。
2. 數據報套接字(SOCK_DGRAM)
提供?連接服務。數據包以獨?數據包的形式被發送,不提供?差錯 ? ?保證,數據可能丟失或重復,順序發送,可能亂序接收。
3.原始套接字(SOCK_RAW)
可以對較低層次協議,如IP、ICMP直接訪問。功能強?但使?較為不便, 主要?于?些協議的開發。
socket在所有的?絡操作系統中是必不可少,它是網絡通信中應?程序對應的進程
和網絡協議之間的接?。

2.網絡字節序

計算機數據存儲有兩種字節優先順序:高位字節優先低位字節優先。Internet上數據以?位字節優先順序在網絡上傳輸,所以對于在內部是以低位字節優先?式存儲數據的機器,在Internet上傳輸數據時就需要進?轉換,否則就會出現數據不?致。
內存中存儲的多字節數據相對于內存地址有大端小端之分,網絡數據流同樣有大端小端之分。
主機字節序:就是自己的主機內部,內存中數據的存放?式,可以分為兩種: ?
大端字節序(big-endian):按照內存的增長方向,高位數據存儲于低位內存中
小端字節序(little-endian):按照內存的增長方向,高位數據存儲于?位內存中。
?多數Intel兼容機都采??端模式。
編寫一個簡單程序判斷當前機器是大端機還是小端機
test.c
#include <stdio.h>int main()
{unsigned int num = 0x12345678;unsigned char *p = (unsigned char *)&num;if (*p == 0x78){printf("當前是小端機\n");}else if (*p == 0x12){printf("當前是大端機\n");}else{printf("無法判斷\n");}return 0;
}

?絡字節順序: 是TCP/IP中規定好的?種數據表示格式,它與具體的CPU類型、操作系統等?關,?絡數據流同樣有?端?端之分,也就是說,當接收端收到第?個字節的時候,它將這個字節作為?位字節還是低位字節處理.從?可以保證數據在不同主機之間傳輸時能夠被正確解釋。網絡字節順序采?big endian排序?式(?位字節優先)。
?般考慮到計算機中的字符與?絡中的字符存儲順序是不同的,當計算機中的整數與?絡中的整數進?交換時,需要相關的函數進?轉換。
傳輸字節時可分兩種情況:
1.傳輸?個?單字節數據,這時要轉換成?絡字節順序,
2.傳輸?個單字節數據,這時就不需要轉換了,因為單字節數據?所謂G高或低字節優先
涉及相關函數如下:
#include <arpa/inet.h>
/*主機字節順序 --> ?絡字節順序*/
uint32_t htonl(uint32_t hostlong); /* IP*/
uint16_t htons(uint16_t hostshort); /* 端?*/
in_addr_t inet_addr(const char *cp); //將?個點分字符串IP地址轉換為?個32位的?絡序列IP地址。所屬頭?件:Winsock2.h (windows)? ? ? ?arpa/inet.h (Linux)
/*?絡字節順序 --> 主機字節順序*/
uint32_t ntohl(uint32_t netlong); /* IP*/
char *inet_ntoa(struct in_addr in);//將?個32位的?絡字節序轉換為?個點分?進制字符串
struct in_addr //結構體in_addr ?來表示?個32位的IPv4地址。
{
in_addr_t s_addr; //in_addr_t ?般為 32位的unsigned int,其字節順序為?絡順序
};

二,基于TCP/IP協議的socket通信

socket抽象層與體系結構關系示意圖

當我們使?不同的協議進?通信時就得使?不同的接?,還得處理不同協議的各種細節,這就增加了開發的難度,軟件也不易于擴展。于是就出現了socket,socket屏蔽了各個協議的通信細節,使得程序員無需關注協議本身,直接使?socket提供的接?來進?互聯的不同主機間的進程的通信。

?們把socket設計成?件,通過描述符我們可以定位到具體的file結構體,file結構體中有個f_type屬性,標識了?件的類型(?如套接?類型,so_pcb結構內包含了當前主機的地址和端?信息,這給結構的編號就是套接字的?件描述符,和進程的pcb塊類似)

1.?基于TCP/ip的相關通信api簡介

當進程創建?個socket套接字時,操作系統會相應的創建出?個由?件系統管理的socket對象,這個socket對象中包含:發送緩沖區、接收緩沖區、等待隊列、 等成員。每?個tcp的套接字(socket)都有兩個緩沖區,發送緩沖區和接收緩沖區都是先進先出的隊列。
其中,等待隊列是?常重要的成員。操作系統會將調動recv阻塞的進程掛在對應socket的等待隊列
中(只是進程的引?,不是進程本身),此時進程進?阻塞態,不會占?CPU資源。
當socket上收到數據后,操作系統會將該socket從等待隊列中重新放回到?作隊列,繼續執?。

1)創建套接字

#include <sys/types.h> /* See NOTES */#include <sys/socket.h>//建??個新的socket(即為建??個通信端?)int socket(int domain, int type, int protocol);成功返回?負的套接字描述符,失敗返回 -1參數說明:domain:即協議域,?稱為協議族(family)Name Purpose Man pageAF_UNIX, AF_LOCAL Local communication unix(7)AF_INET IPv4 Internet protocols ip(7)AF_INET6 IPv6 Internet protocols ipv6(7)AF_IPX IPX - Novell protocolsAF_NETLINK Kernel user interface device netlink(7)AF_X25 ITU-T X.25 / ISO-8208 protocol x25(7)AF_AX25 Amateur radio AX.25 protocolAF_ATMPVC Access to raw ATM PVCsAF_APPLETALK AppleTalk ddp(7)AF_PACKET Low level packet interface packet(7)AF_ALG Interface to kernel crypto APItype:SOCK_STREAM TCPSOCK_DGRAM UDPSOCK_SEQPACKET 為最??度固定的數據報提供有序、可靠、基于雙向連接的數據
傳輸路徑SOCK_RAW 原始套接字SOCK_RDM 提供不保證排序的可靠數據報層。protocol:?于指定socket所使?的傳輸協議編號,通常默認設置為0即可0選擇type類型對應的默認協議;IPPROTO_TCP:TCP傳輸協議;IPPROTO_UDP:UDP傳輸協議;

2)綁定套接字和服務器地址

注意:?般來說,?個端?釋放后會等待兩分鐘之后才能再被使?,SO_REUSEADDR是讓端?釋放后?即就可以被再次使?。SO_REUSEADDR?于對TCP套接字處于TIME_WAIT狀態下的socket,才可以重復綁定使?。server程序總是應該在調?bind()之前設置SO_REUSEADDR套接字選項。先調?close()的??會進?TIME_WAIT狀態。
#include <sys/types.h> /* See NOTES */#include <sys/socket.h>//?來給參數sockfd的socket設置?個名稱,該名稱由addr參數指向的sockadr結構int bind(int sockfd, const struct sockaddr *addr, socklen_t addrle
n);返回說明:成功返回 0 失敗返回 -1?途:主要?與在TCP中的連接形參說明:sockfd 套接字?件描述符addr 服務器地址信息struct sockaddr {sa_family_t sa_family;char sa_data[14];}但在編程中?般使?下邊這種等價結構sockaddr,對于IPV4我們常?這個結構注意:使?該結構需要包含:#include <netinet/in.h>頭?件 ****struct sockaddr_in {sa_family_t sin_family; IPV4對應AF_INET//htons()u_int16_t sin_port; 端?號//sin_port存儲端?
號(使??絡字節順序)struct in_addr sin_addr; IP地址 //inet_addr()將
字符串形象ip轉?絡字節序};/* Internet address. */struct in_addr {u_int32_t s_addr; IP地址};addrlen addr的?度 sizeof(struct sockaddr)//如果使?IPV6地址,需要?這個結構來定義變量存放ipv6相關信息 struct sockaddr_in6 {sa_family_t sin6_family; /* AF_INET6 */in_port_t sin6_port; /* port number */uint32_t sin6_flowinfo; /* IPv6 flow information */struct in6_addr sin6_addr; /* IPv6 address */uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */};struct in6_addr {unsigned char s6_addr[16]; /* IPv6 address */};

3)監聽模式

#include <sys/socket.h>//?于等待參數sockfd的scoket連線int listen(int sockfd, int backlog);返回值說明:成功返回0,失敗返回-1sockfd 套接字?件描述符backlog 監聽隊列?度(等待連接的客戶端的個數)缺省值20,最?值為128即為規定了內核應該為相應套接?排隊的最?連接個數

4)等待客戶端連接的到來

#include <sys/types.h> #include <sys/socket.h> //接收socket的連線int accept(int sockfd, struct sockaddr *addr, socklen_t *addrle
n); 返回值說明:成功返回連接的客戶端的套接字?件描述符 失敗返回 -1參數說明:sockfd 服務器套接字?件描述符addr 客戶端信息地址,做返回值?的,不獲取可以直接輸?NULLaddrlen addr的?度,注意是?個指針類型 ,傳?指定地址的?度,不指定
則NULL

5)客戶端建立socket連線

#include <sys/types.h> /* See NOTES */#include <sys/socket.h>/*?于將參數sockfd的socket連接到參數addr指定的?絡地址*/int connect(int sockfd, const struct sockaddr *addr, socklen_t addrl
en);addr:服務端的地址addrlen:為scokarr的結構?度返回值:返回0時,表明該連接已經成功建?,返回-1時,表明該連接發?了錯誤,即沒有成
功建?連接。注意:connect() 函數不阻塞,所以在使?之前要確保服務器已經進?等待連接狀態。

6)讀寫函數

讀(read/recvfrom/msgrcv):
讀的本質來說其實不能是讀,在實際中, 具體的接收數據不是由這些調?來進?,是由于系統底層?動完成的。read 也好,recv 也好只負責把數據從底層緩沖copy 到我們指定的位置。
寫(send/write):
寫的本質也不是進?發送操作,?是把?戶態的數據copy 到系統底層去,然后再由系統進?發送操作,send,write返回成功,只表示數據已經copy 到底層緩沖,?不表示數據已經發出,更不能表示對?端?已經接收到數據。
#include<unistd.h>
//將數據寫?已打開的?件內,寫?count個字節到參數fd所指的?件內。
ssize_t write(int fd,const void*buf,size_t count);
//從已打開的?件中讀取數據
ssize_t read(int fd,void*buf,size_t count);
返回值:讀取到的實際數據數,如果返回0表示已經到達?件末尾或?可讀取的數據,當read()函數
返回值為0時,
表示對端已經關閉了 socket,這時候也要關閉這個socket,否則會導致socket泄露。
當read()或者write()函數返回值?于0時,表示實際從緩沖區讀取或者寫?的字節數?
當read()或者write()返回-1時,?般要判斷errno
?般是讀寫操作超時了,還未返回。這個超時是指socket的SO_RCVTIMEO與SO_SNDTIMEO兩個屬
性。
所以在使?阻塞socket時,不要將超時時間設置的過?。不然返回了-1,
你也不知道是socket連接是真的斷開了,還是正常的?絡抖動。?般情況下,阻塞的socket返回
了-1,
都需要關閉重新連接。
Close()和shutdown()——結束數據傳輸
當所有的數據操作結束以后,你可以調?close()函數來釋放該socket,從?
停?在該socket上的任何數據操作:close(sockfd);

2.并發服務器

TCP服務器?次只能接收?個客戶端的連接的請求,只有在該客戶端的所有請求都滿?后,服務器才可以繼續響應后邊的請求,如果?個客戶端占?服務器不釋放,其他客戶端都不能?作了,因此上述的TCP服務器?稱為循環服務器,鑒于TCP循環服務器的缺陷,很少TCP服務器采?。
為了解決循環TCP服務器的缺陷,?們?想出了并發服務器模型。并發服務器的思想為:每?個客戶端的請求并不由服務器直接處理,?是由服務器創建?個子進程或?線程來解決。
示例程序:
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <netinet/in.h>#define PORT 8888
#define BUF_SIZE 1024// 線程函數:處理一個客戶端
void *handle_client(void *arg)
{int client_sock = *(int *)arg;free(arg);char buffer[BUF_SIZE];int n;while ((n = read(client_sock, buffer, BUF_SIZE - 1)) > 0){buffer[n] = '\0';printf("[客戶端消息] %s\n", buffer); // 在服務器端顯示客戶端消息}printf("客戶端斷開連接。\n");close(client_sock);return NULL;
}int main()
{int server_sock, *client_sock;struct sockaddr_in server_addr, client_addr;socklen_t client_len = sizeof(client_addr);// 創建socketserver_sock = socket(AF_INET, SOCK_STREAM, 0);if (server_sock < 0){perror("socket");exit(EXIT_FAILURE);}int opt = 1;setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = INADDR_ANY;server_addr.sin_port = htons(PORT);if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){perror("bind");close(server_sock);exit(EXIT_FAILURE);}if (listen(server_sock, 5) < 0){perror("listen");close(server_sock);exit(EXIT_FAILURE);}printf("服務器已啟動,監聽端口 %d...\n", PORT);while (1){client_sock = malloc(sizeof(int));*client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_len);if (*client_sock < 0){perror("accept");free(client_sock);continue;}printf("新客戶端連接:%s:%d\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));pthread_t tid;pthread_create(&tid, NULL, handle_client, client_sock);pthread_detach(tid);}close(server_sock);return 0;
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>#define PORT 8888
#define BUF_SIZE 1024int main()
{int sock;struct sockaddr_in server_addr;char buffer[BUF_SIZE];// 創建socketsock = socket(AF_INET, SOCK_STREAM, 0);if (sock < 0){perror("socket");exit(EXIT_FAILURE);}server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服務器IPif (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){perror("connect");close(sock);exit(EXIT_FAILURE);}printf("已連接到服務器,現在可以輸入消息...\n");while (1){// 從標準輸入讀取消息printf("輸入: ");if (fgets(buffer, BUF_SIZE, stdin) == NULL)break;// 發送到服務器write(sock, buffer, strlen(buffer));}close(sock);return 0;
}

運行結果:

三,基于UDP/IP協議的socket通信

?基于UDP/IP通信的相關api簡介

1)發送UDP報格式數據

#include <sys/types.h>
#include <sys/socket.h>
//把UDP數據報發給指定地址
int sendto (int sockfd, const void *buf, int len, unsigned int flags, const struct sockaddr *to, int tolen);
參數說明:sockfd 套接字?件描述符buf 存放發送的數據len 期望發送的數據?度flags 0to struct sockaddr_in類型,指明UDP數據發往哪?報tolen: 對?地址?度,?般為:sizeof(struct sockaddr_in)。

2)接收UDP報格式數據

#include <sys/types.h>
#include <sys/socket.h>
//接收UDP的數據
int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
參數意義和sentdo類似,其中romlen傳遞是接收到地址的?度
例如 int p=sizeof(struct adrr_in),最后?個參數就傳為&p
注意:如果數據流量突然增?,也可以通過如下函數設置發送或接收緩沖區的大小。
調整UDP緩沖區??:使用函數setsockopt()函數修改接收緩沖區大小
int setsockopt(int sockfd,int level,int optname,const void *optval,socklen_t optlen);
level:選項定義的層次:?持soL_SOCKET,IPPROTO_TCP,IPPROTO_IP和
IPPROTO_IPV6optname。
需設置得選項so_RCVBUF(接收緩沖區),So_SNDBUF(發送緩沖區)

3) 創建套接字 (Socket)

在進行任何網絡通信之前,應用程序必須先向操作系統請求一個網絡通信的“端點”,這個端點就是套接字。

#include <sys/types.h>
#include <sys/socket.h>// 創建一個套接字
int socket(int domain, int type, int protocol);```**參數說明:***   `domain`: 指定通信協議族。對于IPv4網絡通信,這個值通常是 `AF_INET`。
*   `type`: 指定套接字的類型。*   對于UDP通信,這個值必須是 `SOCK_DGRAM` (Datagram),表示這是一個提供數據報服務的套接字,不建立連接,每個數據包都是獨立的。*   (作為對比,TCP使用 `SOCK_STREAM`)
*   `protocol`: 協議類型。通常設置為 `0`,讓系統根據 `domain` 和 `type` 自動選擇最合適的協議(對于 `AF_INET` 和 `SOCK_DGRAM`,系統會選擇IPPROTO_UDP)。**返回值:***   **成功**:返回一個新的文件描述符 (一個非負整數),代表創建的套接字。后續的所有操作都將通過這個文件描述符進行。
*   **失敗**:返回 `-1`,并設置全局變量 `errno` 來表示錯誤原因。**示例:**
```c
int sockfd;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {perror("socket creation failed");exit(EXIT_FAILURE);
}

4) 綁定地址和端口 (Bind)

對于需要接收數據的UDP程序(通常是服務器端),必須將其創建的套接字與一個具體的IP地址和端口號關聯起來。這樣,當網絡中有數據包發送到這個IP和端口時,操作系統才知道應該將數據交給哪個程序處理。

#include <sys/types.h>
#include <sys/socket.h>// 將套接字與一個地址綁定
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

參數說明:

  • sockfd:?socket()?函數返回的套接字文件描述符。

  • addr: 一個指向?struct sockaddr?結構體的指針,但實際使用中通常傳入一個?struct sockaddr_in?結構體(需要進行類型強制轉換)。該結構體包含了要綁定的IP地址和端口號。

  • addrlen:?addr?結構體的長度,通常為?sizeof(struct sockaddr_in)。

struct sockaddr_in?結構體詳解:

struct sockaddr_in {sa_family_t    sin_family; // 地址族, 必須是 AF_INETin_port_t      sin_port;   // 端口號 (需要使用 htons() 轉換)struct in_addr sin_addr;   // IPv4 地址
};struct in_addr {uint32_t       s_addr;     // 32位的IPv4地址 (需要使用 inet_addr() 或 INADDR_ANY)
};

注意:?端口號和IP地址必須從“主機字節序”轉換為“網絡字節序”。通常使用?htons()?(Host to Network Short) 來轉換端口,使用?inet_addr("127.0.0.1")?或?INADDR_ANY?(表示綁定到本機所有IP地址) 來設置地址。

返回值:

  • 成功:返回?0。

  • 失敗:返回?-1,并設置?errno。

示例:

struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY; // 監聽任意網卡的請求
servaddr.sin_port = htons(8888);       // 綁定到8888端口if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {perror("bind failed");exit(EXIT_FAILURE);
}

對于UDP客戶端,通常不需要顯式調用?bind()。因為在第一次調用?sendto()?時,操作系統會自動為其分配一個臨時的端口號。

5) 關閉套接字 (Close)

當通信結束時,應該釋放套接字占用的系統資源。這個操作就像關閉一個文件一樣。

#include <unistd.h>// 關閉一個文件描述符
int close(int fd);

參數說明:

  • fd: 需要關閉的文件描述符,這里就是?socket()?返回的套接字文件描述符。

返回值:

  • 成功:返回?0。

  • 失敗:返回?-1,并設置?errno。

示例:

printf("通信結束,關閉套接字。\n");
close(sockfd);

總結:一個典型UDP程序的API調用流程

  • 服務器端:

    1. socket(): 創建套接字。

    2. bind(): 為套接字綁定一個固定的IP和端口,以便客戶端能找到它。

    3. recvfrom(): 循環等待并接收來自客戶端的數據。

    4. sendto(): (可選)向客戶端發送響應。

    5. close(): 程序結束時關閉套接字。

  • 客戶端:

    1. socket(): 創建套接字。

    2. sendto(): 向服務器的指定IP和端口發送數據。

    3. recvfrom(): (可選)接收來自服務器的響應。

    4. close(): 程序結束時關閉套接字。

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

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

相關文章

維度躍遷:當萬物皆成電路,智能將從“擁有”變為“存在”

我們習以為常的電子世界&#xff0c;其本質是一個由電路構成的精密宇宙。而一場從二維到三維的終極變革&#xff0c;正在悄然醞釀&#xff0c;它將徹底顛覆我們創造和交互的方式。一、電子世界的本質&#xff1a;一切都是電路 在深入未來之前&#xff0c;我們首先要理解當下。電…

大語言模型預訓練數據采集與清洗技術實踐:從語料到知識庫的全流程優化

大語言模型(LLM)的性能上限由 “數據質量 數據規模 數據多樣性” 共同決定 —— 預訓練階段的海量語料決定模型的泛化能力與語言理解基礎,而知識庫數據則決定模型的知識準確性與領域專業性。當前 LLM 落地面臨的核心痛點之一,便是 “數據臟、處理難、知識雜”:預訓練語料…

模擬音頻采集設備的制作

模擬音頻程序與設備的制作 需要設備 esp32s3 pcm1808 pcm5102(非必須) 程序界面 程序代碼 代碼鏈接

Java Modbus通信實戰(四):Modbus通信測試與故障排查

在工業現場&#xff0c;設備通信系統就像工廠的神經網絡&#xff0c;連接著各種傳感器、控制器和執行器。當你搭建好這套系統后&#xff0c;最關鍵的一步就是全面測試&#xff0c;確保每個環節都能正常工作。 就像汽車出廠前要經過嚴格的路試一樣&#xff0c;Modbus RTU通信系統…

少兒編程C++快速教程之——1. 基礎語法和輸入輸出

1. 歡迎來到C編程世界&#xff01; 1.1 什么是編程&#xff1f; 編程就像是給計算機寫一份詳細的"說明書"&#xff0c;告訴它該做什么、怎么做。C是一種強大的編程語言&#xff0c;可以用來創建游戲、應用程序和各種有趣的軟件&#xff01; 1.2 第一個C程序&#xff…

arma::imat22

arma::imat22 是 Armadillo C 線性代數庫中定義的一個固定大小的 2x2 有符號整數矩陣類型。它主要用于處理小型、維度在編譯時已知的整數矩陣&#xff0c;因其在棧上分配內存&#xff0c;故通常比動態矩陣有更高的效率。 下面是一個匯總了 arma::imat22 主要特性的表格&#xf…

狗都能看懂的HunYuan3D 1.0詳解

HunYuan3D 1.0 HunYuan3D 1.0是2024年9月發布的一篇論文。雖然站在現在的時間節點&#xff0c;HunYuan3D系列已經出到2.5了&#xff0c;但是1.0版本的改進思路&#xff0c;和它trick集成的做法&#xff0c;還是很值得學習的。由于文章用到了很多技術&#xff0c;由于篇幅有限&a…

踏腳邁入奇幻樂園

每天早上上班的路上都會經過一個小花園。它被夾在丁字路口的拐角&#xff0c;面積不大&#xff0c;匆匆而過的行人都不會注意到它。但如果順著幾個不起眼的入口走進去&#xff0c;里面卻是別有洞天。清早的街道還沒有車水馬龍的喧嘩&#xff0c;花園里靜悄悄的。各式各樣的花草…

內存越界引發線程函數調用堆棧回溯異常以及INT 3軟中斷實戰分析案例分享

目錄 1、問題說明 2、導出dump文件時只是遇到了INT 3軟中斷&#xff0c;并沒有發生異常崩潰 3、函數中發生了棧內存越界&#xff0c;導致線程的棧回溯出異常&#xff0c;堆棧中只顯示一行函數調用記錄 3.1、處理Json數據時產生了異常 3.2、函數中發生棧內存越界&#xff0…

LeetCode 240: 搜索二維矩陣 II - 算法詳解(秒懂系列

文章目錄LeetCode 240: 搜索二維矩陣 II - 算法詳解題目描述Java解決方案算法思路核心理念為什么選擇右上角&#xff1f;可視化演示過程示例1&#xff1a;查找 target 5示例2&#xff1a;查找 target 20 (不存在)算法分析時間復雜度空間復雜度算法優勢關鍵要點擴展思考LeetCo…

洛谷 B4071 [GESP202412 五級] 武器強化

思考難度低&#xff0c;但是代碼難度相對較高的題&#xff0c;故做個記錄。首先&#xff0c;題目說了要花費最少的錢&#xff0c;所以我們每次拿最便宜的材料給武器1思想&#xff1a;每次都拿最便宜的材料然后考慮一下這個思想是否正確&#xff0c;找一下反例&#xff0c;每次拿…

SQL工具30年演進史:從Oracle到Navicat、DBeaver,再到Web原生SQLynx

目錄 一、1990s&#xff1a;廠商自帶的數據庫工具時代 二、2000s&#xff1a;Navicat等商業數據庫管理工具崛起 三、2010s&#xff1a;DBeaver等開源SQL工具興起 四、2020s&#xff1a;SQLynx&#xff0c;Web原生數據庫管理工具 五、SQL工具30年時間線對比 六、總結&…

C語言制作掃雷游戲(拓展版賦源碼)

目錄 引言&#xff1a; 三個新功能實現 1.可以選擇難度或自定義 實現難點解析 代碼實現&#xff08;附源碼&#xff09; 掃雷.c game.h game.c 2.對選擇位置進行標記或取消標記 一.框架 我們先理一下思路 如何構造框架 二.取消標記函數 三.標記函數 四.加入清屏&#xff0c;進…

Python快速入門專業版(十):字符串特殊操作:去除空格、判斷類型與編碼轉換

目錄引1.去除空格&#xff1a;清理字符串的實用技巧1.1 三類去空格方法&#xff1a;strip()、lstrip()、rstrip()1.2 實戰案例&#xff1a;處理用戶輸入的空格問題2.判斷類型&#xff1a;驗證字符串內容的特性2.1 常用類型判斷方法2.2 實戰案例&#xff1a;驗證用戶輸入的合法性…

Gamma AI:AI演示文稿制作工具,高效解決PPT框架搭建難與排版耗時問題

你做 PPT 的時候是不是也常陷入 “兩難”&#xff1f;要么對著空白幻燈片發呆&#xff0c;不知道怎么搭框架 —— 比如要做 “產品季度迭代復盤”&#xff0c;既想放數據又想講問題&#xff0c;結果頁面堆得像亂燉&#xff1b;要么好不容易湊完內容&#xff0c;又花兩小時調排版…

【應用案例】AI 給醫用過濾器 “找茬”:3 大難點 + 全流程解決方案

【應用案例】AI 給醫用過濾器 “找茬”&#xff1a;3 大難點 全流程解決方案&#x1f3af;醫用過濾器進行醫療AI檢測&#x1f3af;先看痛點&#xff1a;醫用過濾器檢測難在哪&#xff1f;&#x1f3af;AI檢測方案&#xff1a;3步實現“零漏檢”1. 硬件定制&#xff1a;讓缺陷“…

【數據庫相關】TxSQL新增數據庫節點步驟

TxSQL新增數據庫節點步驟準備工作與注意事項具體操作步驟第 1 步&#xff1a;在主庫上創建復制專用賬號第 2 步&#xff1a;對主庫進行鎖表并獲取二進制日志坐標第 3 步&#xff1a;備份主庫數據并傳輸到新從庫第 4 步&#xff1a;主庫解鎖第 5 步&#xff1a;在新從庫服務器上…

Jmeter快速安裝配置全指南

1、JDK安裝(Java Development Kit) 1.1.JDK下載 JDK下載址&#xff1a; Java Downloads | Oracle &#xff08;jdk-8u211-windows-x64.exe&#xff09; Android 基于 Java 語言開發&#xff0c;所以必須安裝Java環境&#xff0c;Java 環境分JDK 和JRE &#xff0c;JDK提…

設計模式最佳實踐 - 模板模式 + 責任鏈模式

廢話不多說&#xff0c;直接切入正題&#xff0c;本篇要講的是 模板模式 責任鏈模式 實踐。該最佳實踐本身就是一種對 責任鏈模式的增強&#xff0c;模板模式通過 父類 強耦合&#xff0c;預定義好 責任鏈 next 方法 的前后一些切面行為&#xff0c;優雅簡潔。先上示例&#x…

Python快速入門專業版(十一):布爾值與None:Python中的“真假”與“空值”(附邏輯判斷案例)

目錄引言&#xff1a;為什么“真假”與“空值”是編程的核心邏輯1.布爾值&#xff08;bool&#xff09;&#xff1a;Python中的“真”與“假”1.1 布爾值的基礎特性1.2 布爾運算&#xff1a;and、or、not的邏輯規則代碼示例&#xff1a;基礎布爾運算進階特性&#xff1a;短路求…