Linux:套接字

從進程的視角來看,網絡通信就是一個主機上的進程和另外一個主機上的進程進行信息傳遞,因此對于操作系統而言,網絡通信就是一種進程間通信的方式。

不過這種進程間通信有特殊之處:同一臺主機下可以通過進程ID來標識一個唯一的進程,兩個進程通過進程ID來相互識別,可是對于不同主機上的兩個進程而言,知道對方進程ID并沒有什么意義,因此需要另外一種方式來相互識別:IP+端口號(port)

其中IP用于在局域網內確定唯一一臺主機,而規定一個端口號只能被一個進程占用,通過IP+端口號的方式,兩個進程就能識別對方并進行通信。

端口號

1.是傳輸層協議的內容,用來標識一臺主機中的進程

2.是一個2字節,16比特位的整數

3.一個端口號只能被一個進程占用,一個進程可以占用多個端口號

4.IP地址+端口號能夠表示網絡上的某臺主機的一個進程

端口號范圍

0 - 1023: 知名端口號, HTTP, FTP, SSH 等這些廣為使用的應用層協議, 他們的端口號都是固定的.

1024 - 65535: 操作系統動態分配的端口號. 客戶端程序的端口號, 就是由操作系統從這個范圍分配的.

Socket API

操作系統將網絡通信抽象為?Socket(套接字),socket是一個五元組標識,?完整定義為:

[協議, 源IP, 源Port, 目標IP, 目標Port](例如?[TCP, 192.168.1.2:54321, 93.184.216.34:80])。

在Linux下,socket通過一個文件描述符sockfd來進行描述和管理,每個sockfd對應一個socket,進而對應一個IP+port,由于每個進程有獨立的文件描述符表,這使得該文件描述符sockfd被一個進程獨享,印證了上文IP+Port確定一臺主機上的唯一進程,這同時意味著我們可以用文件IO的方式來進行網絡通信,當然這里我們還是循序漸進,先來介紹socket的相關接口:

socket主要接口依賴于頭文件:

#include <sys/socket.h>

創建一個sockfd:

int socket(int domain, int type, int protocol);

domain: 指定通信協議族,例如: AF_INET: IPv4 網絡協議。 AF_INET6: IPv6 網絡協議。 AF_UNIX: 本地進程間通信。

type: 指定套接字類型,例如: SOCK_STREAM: 面向連接的流式套接字(如 TCP)。 SOCK_DGRAM: 無連接的數據報套接字(如 UDP)。 SOCK_RAW: 原始套接字,用于底層協議訪問(不常用)。

protocol: 指定具體協議,通常設置為?0,表示使用默認協議。例如: 對于 SOCK_STREAM,默認是 TCP。 對于 SOCK_DGRAM,默認是 UDP。

返回值為sockfd

將一個sockfd與一個端口號進行綁定?

int bind(int socket, const struct sockaddr *address,socklen_t address_len);

(1)參數 sockfd ,需要綁定的socket。

(2)參數 addr ,一個存放目的地址和目的端口號的結構體,需要進行初始化。

(3)參數 addrlen ,表示 addr 結構體的大小

(4)返回值:成功則返回0 ,失敗返回-1,錯誤原因存于 errno 中。如果綁定的地址錯誤,或者端口已被占用,bind 函數一定會報錯,否則一般不會返回錯誤。

sockaddr

這個sock_addr就是內核態中的socket從用戶態中獲取地址族和目標IP+port的方式:

struct sockaddr 
{  sa_family_t sin_family;//地址族char sa_data[14]; //14字節,包含套接字中的目標地址和端口信息               
}; 

不難發現該數據結構有一個缺陷:端口號和ip地址混在一塊了,這明顯不方便我們進行初始化

為了解決此問題,又定義了sockaddr_in,依賴于頭文件:

#include<netinet/in.h>

所以實踐中,我們會先定義一個sockaddr_in來完成初始化,再將其指針強轉為sockaddr*用于綁定

這里還有一個十分重要的細節問題:網絡字節序

sin_port和sin_addr都必須是網絡字節序(大端模式,低地址高字節),一般可視化的數字都是主機字節序(小端模式,低地址低字節)。

這里用一個簡單的例子來幫助理解:

對于數據 0x12345678,假設從地址0x4000開始存放,在大端和小端模式下,存放的位置分別為:

總之,我們給sin_port和sin_addr進行初始化時,要進行字節序的轉換,這里需要用到兩個函數:

htons()作用是將端口號由主機字節序轉換為網絡字節序的整數值。(host to net)

inet_addr()作用是將一個IP字符串轉化為一個網絡字節序的整數值,用于sockaddr_in.sin_addr.s_addr。

需要頭文件:

#include <arpa/inet.h>

是不是有些復雜,我們實際演示一下:

創建并綁定一個UDP協議的socket:

int port=8080;
char ip[16]=192.168.1.0;int server_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (server_fd < 0) 
{perror("socket creation failed");return 1;
}struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(ip);
//推薦這么寫:
//server_add.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port = htons(port); if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) 
{perror("bind failed");close(server_fd);return 1;
}

上述接口是UDP和TCP公用的,下面先介紹一下這兩個協議的特點,再分別介紹各自的接口

UDP

核心思想:?“盡最大努力交付” (Best Effort)。簡單、快速、無連接。

關鍵特性:

無連接: 發送數據之前不需要預先建立連接。每個數據包(稱為數據報)都是獨立處理的。

不可靠 :?不保證數據報一定能到達目的地,不保證按發送順序到達,也不保證數據報只到達一次。可能發生丟失、重復、亂序。

面向報文:?對應用層交下來的報文,添加 UDP 首部后就直接交給網絡層 IP。接收方 UDP 對 IP 層交上來的 UDP 數據報,去除首部后就原封不動地交付給上層應用進程。應用程序需要自己處理報文邊界。

無擁塞控制:?UDP 本身不會根據網絡狀況調整發送速率。如果發送太快導致網絡擁堵,UDP 包會被大量丟棄,但它本身不會主動慢下來。

首部開銷小:?UDP 首部固定為 8 字節。

支持單播、多播、廣播:?非常靈活。

緩沖區

UDP 沒有真正意義上的發送緩沖區,調用 sendto 會直接交給內核, 由內核將數 據傳給網絡層協議進行后續的傳輸動作;

UDP 具有接收緩沖區,但是這個接收緩沖區不能保證收到的 UDP 報的順序和發送 UDP 報的順序一致;

如果緩沖區滿了, 再到達的 UDP 數據就會被丟棄;

UDP 的 socket 既能讀, 也能寫, 這個概念叫做全雙工

UDP報頭

UDP在內核中通過sk_buff進行管理,其中有一個指向報文起始位置的指針data,由于UDP的報頭是固定長度8B,所以只需將data指針移動8B即可

UDP雖然不可靠,但是會保證內容的正確性,其中UDP校驗和就是一種檢驗UDP數據包是否有誤的校驗機制,它通過某種算法將UDP數據包中的所有數據進行計算然后存儲在報頭字段中,以便確保接收方在收到數據包后進行校驗。如果校驗失敗的話,就直接把這個數據包丟棄

我們注意到, UDP協議首部中有一個16位的最大長度. 也就是說一個UDP能傳輸的數據最大長度是64K(包含UDP首部). ? 然而64K在當今的互聯網環境下, 是一個非常小的數字.如果我們需要傳輸的數據超過64k,就需要在應用層手動的分包, 多次發送并在接收端手動拼裝(面向數據報)?

send和recvfrom

由于UDP傳輸數據是面向報文的,因此我們不能直接用面向字節流的文件IO接口,而是需要使用函數recvfrom()來接收數據,使用send()來發送數據

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
  1. 第一個參數sockfd:正在監聽端口的套接口文件描述符,通過socket獲得
  2. 第二個參數buf:接收緩沖區,往往是使用者定義的數組,該數組裝有接收到的數據
  3. 第三個參數len:接收緩沖區的大小,單位是字節
  4. 第四個參數flags:填0即可
  5. 第五個參數src_addr:指向發送數據的主機地址信息的結構體,也就是我們可以從該參數獲取到數據是誰發出的
  6. 第六個參數addrlen:表示第五個參數所指向內容的長度
  7. 返回值:成功:返回接收成功的數據長度
  8. 失敗: -1
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
  1. 第一個參數sockfd:正在監聽端口的套接口文件描述符,通過socket獲得
  2. 第二個參數buf:發送緩沖區,往往是使用者定義的數組,該數組裝有要發送的數據
  3. 第三個參數len:發送緩沖區的大小,單位是字節
  4. 第四個參數flags:填0即可
  5. 第五個參數dest_addr:指向接收數據的主機地址信息的結構體,也就是該參數指定數據要發送到哪個主機哪個進程
  6. 第六個參數addrlen:表示第五個參數所指向內容的長度
  7. 返回值:成功:返回發送成功的數據長度
  8. 失敗: -1

通過UDP協議進行通信的流程如下:

下面我們對上述內容進行一個小實踐,實現一個客戶端的本地回顯

目標:客戶端向服務端發送內容,服務器將這些內容再發給客戶端,客戶端打印接收到的內容

客戶端

#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>int main(int argc,char* argv[])
{std::string server_ip=argv[1];uint16_t server_port=std::stoi(argv[2]);int sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){std::cout<<"創建套接字失敗\n";}sockaddr_in server;memset(&server,0,sizeof(server));server.sin_family=AF_INET;server.sin_port=htons(server_port);server.sin_addr.s_addr=inet_addr(server_ip.c_str());while(true){std::cout<<"請輸入:";std::string line;std::getline(std::cin,line);sendto(sockfd,line.c_str(),line.size(),0,(sockaddr*)&server,sizeof(server));sockaddr_in tmp;socklen_t len=sizeof(tmp);char buffer[1024]={0};int ret=recvfrom(sockfd,buffer,sizeof(buffer)-1,0,(sockaddr*)&tmp,&len);if(ret>0){buffer[ret]=0;std::cout<<buffer<<'\n';}}
}

服務端.hpp

#include"Log.h"
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<strings.h>static const int gdefaultsockfd=-1;class UdpServer
{
public:UdpServer(std::string& ip,uint16_t port):sockfd(gdefaultsockfd),ip(ip),port(port){}~UdpServer()=default;void init(){sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){LOG(LogLevel::FATAL)<<"創建套接字失敗";exit(1);}LOG(LogLevel::INFO)<<"創建套接字成功";sockaddr_in local;bzero(&local,sizeof(local));local.sin_family=AF_INET;local.sin_port=htons(port);local.sin_addr.s_addr=inet_addr(ip.c_str());int n=bind(sockfd,(sockaddr*)&local,sizeof(local));if(n<0){LOG(LogLevel::FATAL)<<"套接字綁定失敗";exit(2);}LOG(LogLevel::INFO)<<"套接字綁定成功";}void start(){is_running=true;while(is_running){char buffer[1024];buffer[0]=0;sockaddr_in  peer;socklen_t len=sizeof(peer);ssize_t n=recvfrom(sockfd,buffer,sizeof(buffer),0,(sockaddr*)&peer,&len);if(n>0){buffer[n]=0;std::string echo="server echo#";echo+=buffer;sendto(sockfd,echo.c_str(),echo.size(),0,(sockaddr*)&peer,len);}}}void stop(){is_running=false;}
private:int sockfd;//套接字文件描述符uint16_t port;//端口號std::string ip;//ip地址bool is_running=false;
};

服務端.cc

#include"udp_server.hpp"
#include<memory>int main(int argc,char* argv[])
{std::string ip=argv[1];uint16_t port=std::stoi(argv[2]);std::unique_ptr<UdpServer> udp_server=std::make_unique<UdpServer>(ip,port);udp_server->init();udp_server->start();return 0;
}

分別啟動客戶端和服務端:

服務端

客戶端

測試成功

TCP

Tcp的特性相對于udp較為復雜,因此我們本次只會進行概括性地描述并介紹幾個接口:

有連接,需要客戶端向服務的發起連接請求

可靠傳輸

面向字節流

監聽客戶端的連接請求

int listen(int sockfd, int backlog);
  • 功能:將套接字設置為監聽狀態,準備接受客戶端的連接請求。
  • 參數:
    • sockfd:已綁定的套接字描述符。
    • backlog:指定等待連接隊列的最大長度。
  • 返回值:成功返回 0,失敗返回 -1。

連接

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 參數:
    • sockfd:套接字描述符。
    • addr:指向服務器的地址結構體。
    • addrlenaddr?結構體的長度。
  • 返回值:成功返回 0,失敗返回 -1。

從已完成連接隊列中取出一個連接,并創建一個新的套接字與客戶端進行通信

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • 參數:
    • sockfd:監聽套接字描述符。
    • addr:用于存儲客戶端的地址信息。
    • addrlen:用于指定?addr?結構體的長度。
  • 返回值:成功返回一個新的套接字描述符用于與客戶端通信,失敗返回 -1。

你可能會疑惑我不是已經通過socket創建了一個sockfd嗎,為什么這里還要創建新的sockfd,其實對于Tcp而言,socket創建的sockfd只是用于接收用戶連接請求的,而真正與用戶通信則是通過accept創建的sockfd進行的,這是因為Tcp通信只能一對一進行,即一個端到端通信占用一個sockfd,要想實現一個服務端與多個客戶端進行通信,就需要建立多個sockfd

而由于Tcp是面向字節流進行傳輸的,因此我們可以直接使用文件IO的接口來讀取和寫入數據

下面是Tcp版本的客戶端回顯:

服務端

#include"inet_addr.hpp"
#include"Log.h"
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<strings.h>static const int gdefaultsockfd=-1;
static const int gbacklog=8;class TcpServer
{
public:TcpServer(std::string& ip,uint16_t port=8080):sockfd(gdefaultsockfd),ip(ip),port(port){}~TcpServer()=default;void init(){sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){LOG(LogLevel::FATAL)<<"創建套接字失敗";exit(1);}LOG(LogLevel::INFO)<<"創建套接字成功";InetAddr local(port);int n=bind(sockfd,local.Addr(),local.Length());if(n<0){LOG(LogLevel::FATAL)<<"套接字綁定失敗";exit(2);}LOG(LogLevel::INFO)<<"套接字綁定成功";if(listen(sockfd,gbacklog)!=0){LOG(LogLevel::FATAL)<<"監聽套接字失敗";exit(3);}}void start(){is_running=true;while(is_running){sockaddr_in  peer;socklen_t len=sizeof(peer);int sock_fd=accept(sockfd,(sockaddr*)&peer,&len);        if(sock_fd<0){LOG(LogLevel::FATAL)<<"接收失敗";}InetAddr clientaddr(peer);HandlerIO(sock_fd,clientaddr);}}void stop(){is_running=false;}
private:void HandlerIO(int fd,InetAddr& client){char buffer[1024];while(true){buffer[0]=0;auto n=read(fd,buffer,sizeof(buffer)-1);if(n>0){buffer[n]=0;std::string echo_string = "server echo: ";echo_string += buffer;LOG(LogLevel::INFO) << buffer;auto m = write(fd,echo_string.c_str(),echo_string.size());}}close(fd);}private:int sockfd;//套接字文件描述符uint16_t port;//端口號std::string ip;//ip地址bool is_running=false;
};

客戶端

#include"inet_addr.hpp"
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<unistd.h>int main(int argc,char* argv[])
{std::string server_ip=argv[1];uint16_t server_port=std::stoi(argv[2]);int sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){std::cerr<<"創建套接字失敗\n";exit(1);}InetAddr server(server_port,server_ip);if(connect(sockfd,server.Addr(),server.Length())!=0){std::cerr<<"連接失敗\n";exit(2);}while(true){std::cout<<"請輸入:";std::string line;std::getline(std::cin,line);auto n=write(sockfd,line.c_str(),line.size());if(n>=0){char buffer[1024];auto m=read(sockfd,buffer,sizeof(buffer)-1);if(m>0){buffer[m]=0;std::cout<<buffer<<'\n';}}}
}

啟動服務端

啟動客戶端

測試成功

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

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

相關文章

Android init.rc詳解3

關于Android Init的詳解&#xff0c;關于Action&#xff0c;Service&#xff0c;Trigger的請參考Android init.rc詳解1&#xff0c;關于Options的請參考Android init.rc詳解2&#xff0c;本章將介紹常見的Commands。 1 Commands bootchart [start|stop] 啟動或停止bootcharti…

Sentinel原理之規則管理

文章目錄1. 基礎知識2. 數據源使用2.1 RedisDatasource2.2 ZookeeperDatasource1. 基礎知識 流量控制規則&#xff08;FlowRule&#xff09;&#xff1a; 閾值類型grade&#xff1a; 0&#xff08;并發線程數&#xff09;&#xff1a;限制同時處理請求的線程1&#xff08;QPS…

系統時鐘配置

STM32F103C8T6的系統時鐘配置成72MHZ1. 什么是 STM32 系統時鐘系統時鐘&#xff08;System Clock&#xff09;是整個 MCU&#xff08;微控制器&#xff09;運行的“節拍信號”&#xff0c;所有 CPU 指令執行、外設操作、定時器計時、總線數據傳輸等&#xff0c;都依賴這個時鐘頻…

Al大模型-本地私有化部署大模型-大模型微調

魔塔社區 魔塔社區平臺介紹 https://www.modelscope.cn/models/Qwen/Qwen2.5-0.5B-Instruct 申請免費的試用機器 如果自己沒有機器 &#xff0c;從這里申請機器 。 下載大模型 pip install modelscope 下載到當前目錄 mkdir -p /root/autodl-tmp/demo/Qwen/Qwen2.5-0.5B-Ins…

國內著名AI搜索優化專家孟慶濤發表《AI搜索內容可信度評估綜合指南》

近日&#xff0c;國內著名AI搜索優化專家、中國GEO生成式引擎優化領域的開拓者與實踐專家孟慶濤正式發布《AI搜索內容可信度評估綜合指南》&#xff0c;針對當前AI生成內容&#xff08;AIGC&#xff09;在搜索場景中可信度參差不齊的痛點&#xff0c;首次提出覆蓋"技術-內…

ruoyi-flowable系統防xss攻擊配置(使用富文本的方式)

背景。開發小程序過程中。用戶使用富文本的方式比較多。但在傳輸后發現如上傳到系統中的圖片鏈接地址被清空了。問題&#xff1a;想要使用富文本。還需要開啟xss過濾。有什么好的解決方案嗎&#xff1f;解決方案&#xff08;我比較傾向的&#xff09;&#xff1a;通過對富文本內…

【opencv-Python學習筆記(2): 圖像表示;圖像通道分割;圖像通道合并;圖像屬性】

目標&#xff1a;1.學會圖像的通道分割與合并2.學會圖像的的常規操作##一些概念&#xff1a;二值圖像&#xff1a;只包含黑色和白色兩種顏色的圖像&#xff0c;1為白色&#xff0c;0為黑色灰度圖像&#xff1a;計算機會將灰度處理為256個灰度級&#xff0c;用區間[0,255]來表示…

Qt——常用Widget(控件)

常用控件 Widget 需要說明&#xff0c;此處說明的控件都繼承于QWiget&#xff0c;因此之前所說的控件屬性&#xff0c;和相關API&#xff0c;在這里的控件都適用 文章目錄常用控件 Widget按鈕類控件QPushButtonQRadioButtonQCheckBox顯示類控件QLabel初識事件LCD NumberProgre…

Cursor/VSCode/VS2017 搭建Cocos2d-x環境,并進行正常的調試和運行(簡單明了)

作者&#xff1a;求一個demo 版權聲明&#xff1a;著作權歸作者所有&#xff0c;商業轉載請聯系作者獲得授權&#xff0c;非商業轉載請注明出處 內容通俗易懂&#xff0c;沒有廢話 廢話不多說&#xff0c;我們直接開始------>>>>>> &#xff01;&#xff…

從 LLM 到自主 Agent:OpenCSG 打造開源 AgenticOps 生態

從 LLM 到自主 Agent&#xff1a;OpenCSG 打造開源 AgenticOps 生態在產業拐點上&#xff0c;交付可持續、可落地的智能體未來在生成式 AI 的時代洪流中&#xff0c;大語言模型&#xff08;LLM&#xff09;已成為行業標配&#xff0c;但如何突破“會說不會做”的局限&#xff0…

黑馬程序員mysql課程中在Linux系統中安裝mysql出現問題

問題描述在安裝linux的最后一步的指令的時候報錯警告&#xff1a;mysql-community-server-8.0.26-1.el7.x86_64.rpm: 頭V3 DSA/SHA256 Signature, 密鑰 ID 5072e1f5: NOKEY 錯誤&#xff1a;依賴檢測失敗&#xff1a;net-tools 被 mysql-community-server-8.0.26-1.el7.x86_64 …

「iOS」————APP啟動優化

iOS學習APP的啟動流程啟動流程缺頁錯誤主要階段pre-main階段main階段啟動優化pre-mainmain階段啟動優化總結流程總結APP的啟動流程 啟動 首先我們來了解啟動的概念&#xff1a; 廣義上的啟動是點擊圖標到首頁數據加載完畢狹義上的啟動是點擊圖標到啟動圖完全消失的第一幀 啟…

知名車企門戶漏洞或致攻擊者遠程解鎖汽車并竊取數據

漏洞概況一家大型汽車制造商的在線系統存在安全漏洞&#xff0c;可能導致客戶數據泄露&#xff0c;并允許攻擊者遠程訪問車輛。該漏洞由安全研究員Eaton Zveare發現&#xff0c;他已于2025年2月向涉事車企報告并促使漏洞修復。Zveare雖未公開車企名稱&#xff0c;但透露這是在美…

Elasticsearch JS 自定義 ConnectionPool / Connection / Serializer、敏感信息脫敏與 v8 平滑遷移

0. 什么時候該用“高階配置”&#xff1f; 復雜網絡/路由需求&#xff1a;自定義“健康節點”判定、權重路由、多租戶隔離。替換 HTTP 棧&#xff1a;接入企業內網網關、打通自研代理/審計、細化超時/連接細節。序列化治理&#xff1a;為超大 JSON、Bulk、查詢串做定制編碼/壓縮…

希爾排序專欄

在排序算法的大家庭中&#xff0c;希爾排序&#xff08;Shell Sort&#xff09;以其獨特的 "分組插入" 思想占據著重要地位。它是對插入排序的創造性改進&#xff0c;通過引入 "增量分組" 策略&#xff0c;大幅提升了排序效率。本文將帶你深入理解希爾排序…

Android 歐盟網絡安全EN18031 要求對應的基本表格填寫

Android 歐盟網絡安全EN18031 要求對應的基本表格填寫 文章目錄Android 歐盟網絡安全EN18031 要求對應的基本表格填寫一、背景二、18031認證預填表格三、其他1、Android EN 18031 要求對應的基本表格小結2、EN 18031的要求表格內容填寫3、一定要做三方認證&#xff1f;4、歐盟網…

《Attention-driven GUI Grounding》論文精讀筆記

論文鏈接&#xff1a;[2412.10840] Attention-driven GUI Grounding: Leveraging Pretrained Multimodal Large Language Models without Fine-Tuning 摘要 近年來&#xff0c;多模態大型語言模型&#xff08;Multimodal Large Language Models&#xff0c;MLLMs&#xff09;的…

PIDGenRc函數中lpstrRpc的由來和InitializePidVariables函數的關系

第一部分&#xff1a;./base/ntsetup/syssetup/setupp.h:404:#define MAX_PID30_RPC 5BOOL InitializePidVariables() {//// Get the Pid from HKEY_LOCAL_MACHINE\SYSTEM\Setup\Pid//Error RegOpenKeyEx( HKEY_LOCAL_MACHINE,((MiniSetup || OobeSetup) ? szFinalPidKeyNa…

Nginx學習筆記(七)——Nginx負載均衡

?? Nginx學習筆記&#xff08;七&#xff09;——Nginx負載均衡 &#x1f4cc; 一、負載均衡核心概念 架構定位&#xff1a; #mermaid-svg-00aCvwmJ40DHNd66 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-00aC…

MQ積壓如何處理

處理消息隊列&#xff08;MQ&#xff09;積壓是一個需要系統化分析的運維挑戰。下面我將結合常見原因&#xff0c;分步驟說明處理方案&#xff0c;并區分應急措施和根本解決方案&#xff1a;?一、快速診斷積壓原因&#xff08;核心&#xff01;&#xff09;???監控告警分析…