Socket 套接字的學習--UDP

上次我們大概介紹了一些關于網絡的基礎知識,這次我們利用編程來深入學習一下

一:套接字Socket

1.1什么是Socket

socket API 是一層抽象的網絡編程接口,適用于各種底層網絡協議,IPv4IPv6,. 然而, 各種網絡協議的地址格式并不相同。
1.2套接字的分類
套接字變成socket 的種類會變得多一些
<1> 本地socket (unix 域間socket)- > sockaddr_un
<2>網絡socket :本地加網絡 - > 用來通信 - > sockaddr_in
<3>最后都統一成了一個套接字,這個套接字作為統一的接口 ,sockaddr
為什么要統一接口呢?如果不同的廠商使用不同的網絡接口,那么任何進程或者是客戶端服務器之間的通信,將會十分麻煩,所以OS 提供了系統調用。所以使用本地或者網絡的時候,要設置它的AF_INET還是AF_UNIX,也就是圖片中的前十六位。然后設置完一些內部的類型等之后,最后都要強轉成sockaddr這個類型的接口,去使用
!c語言中經常使用一些void* ,然后作強轉,那為什么這沒有用void* 最后去強轉成想要的類型,而是直接使用了 這個sockaddr 這個結構體?
當時研究出來網絡接口的時候,c語言還沒有 void * ,其次就是 使用這個 其他類型,因為內部結構可以看出其實是很像c++里面的繼承與多態,這樣的話關聯關系明顯。
:UDP 服務通信
當然,通信的話肯定是兩者以上在通信,我們今天用一個客戶端和一個服務端作為通信的雙方,然后使用UDP 協議進行 云平臺之間的網絡通信 和 云平臺與Windows下的網絡通信。
我們先梳理一下程序流程:
1.1 服務端流程
首先按照我們日常寫的類的話,肯定就是先要初始化一些接口(網絡通信的接口)
其次初始化接口結束后,我們作為服務端,就要等待客戶端的一些需求,我們今天的任務是簡單的通信交流,所以就是等待客戶端的消息,然后收到消息之后就要回話,要知道是誰給我們發的消息,回話的話是給誰發,然后接著等待以后就重復就行了
1.2客戶端流程
作為客戶端,我們要知道給誰發消息,然后等待接受對方回過來的消息,接著重復就好了。細節我們慢慢了解。
1.3 認識創建套接字函數 --socket?
首先呢,我們明確一下頭文件,在學習網絡的過程中,有四個頭文件每次都要包
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

socket?

我們可以用man 直接查這個socket,第一個參數是域或者協議家族,什么意思呢,就是以下這些

看它第二列目的,抵押給是本地通信,第二哥就是域間通信,第三個是IPV4,我們今天就用IPv4規定我們的IP地址。

第二個參數是代表套接字類型,也就是我們使用的TCP協議,還是UDP協議,我們今天用的UDP協議

UDP協議是不連接的,不可靠的,有最大長度的,所以就是 SOCK_DGRAM
第三個參數 默認為 0 就可以了
我們看一下這個函數的返回值
它說這個函數成功,就會返回一個套接字的文件描述符,其實也就是文件描述符,只不過是在網絡中的一個文件,相當于你要是想要在網絡中通信,就必須要在這個文件里寫或者讀。
LOG是我封裝了一個日志,以后會更新這個的。
1.4 bind--綁定網絡信息
我們說了socket 只是給我們創建了一個網絡上通信用的文件,接著我們就要對于這個文件綁定對應的網絡信息,什么信息呢,你要發送,是不是要告訴對方你是誰,對方才能給你回消息。
我們看這個bind,第一個參數不就是我們剛才用socket創建好的套接字返回的描述符嗎
第二個參數 ,struct sockaddr* 這個結構體指針代表者什么呢

這個是什么呢,##這個符號,叫做拼接符,什么啥意思呢,就是前面的參數拼接我后面的family,也就是現在它現在傳的這個參數是sa_ ,那么拼接起來就是sa_family。

也就是sa_family 代表 用AF_INET 等類型初始化

但是我們剛才也說了sockaddr ,是作為最后的網絡的統一的接口的,也就是說,我們在UDP通信的時候今天申請的是網絡通信,所以用的是sockaddr_in,所以我們要用sockaddr_in這個結構體把網絡信息存進去,最后強轉成sockaddr。

我們看這個結構體,第一個就是 sin_family(剛才說的拼接)

第二個 sin_port ->端口號

第三個 sin_addr -> IP地址

所以我們要把我們這個服務端的協議族,端口號,IP地址存進去。

 struct sockaddr_in local;bzero(&local, sizeof(local)); // 最好是先清零再去給它賦值 用memset也可以local.sin_family = AF_INET;local.sin_port = ::htons(_port); // 因為字節序的問題 ,最好是要給轉換成網絡的大端local.sin_addr.s_addr = inet_addr(_ip.c_str());

當大家寫的時候會發現,并不能直接將端口號直接賦值給sin_port,因為什么呢?因為我們上次說了網絡中也是存在大小端的,就是有字節序的問題,所以我們要先轉換成大端,也就是用htons函數

也不能直接把IP地址直接賦值給sin_addr,為什么呢?因為sin_addr它本身是一個結構體,我們還要在結構體里面找結構體成員進行賦值。

,因為我申請的IP用的是string 存放的,所以我想把這個村給s_addr(類型是32位4字節),就要轉換,用inet_addr()把char*轉換成uint32_t 。

把網絡信息存好,就可以進行綁定了。

//int n = bind(_sockfd, CONV(&local), sizeof(local));if (n < 0){LOG(LogLevel::FATAL) << "bind: " << strerror(errno);Die(BIND_ERR);}LOG(LogLevel::INFO) << "bind success";

1.5 接受網絡消息--recvfrom

因為我們的UDP的傳輸報文方式是數據報形式的,所以用recvfrom

第一個參數依舊是老朋友,文教描述符,

第二個是一個void* buffer,意思就是存放信息的地方,

第三個是長度,

第四個默認位0就行,

第五個依舊就是統一接口sockaddr,代表發送端的網絡信息(IP+Port)

第六個的socklen_t 代表sockaddr 的大小是多大的,用一個socklen_t的變量存起來然后取地址就可以。

 ssize_t n = ::recvfrom ( _sockfd,inbuffer,sizeof(inbuffer)-1,0,CONV(&peer),&len);

1.6 sendto 發送消息

依舊是因為UDP傳輸的數據報,選擇sendto

第一個參數依舊是老朋友,文教描述符,

第二個是一個void* buffer,意思就是存放信息的地方,

第三個是長度,

第四個默認位0就行,

第五個依舊就是統一接口sockaddr,代表是發送端的網絡信息

第六個的是sockaddr的大小,直接用sizeof就可以

然后我們處理一下接受到的消息,之后再給客戶端發送過去即可。

void Start(){LOG(LogLevel::INFO) << "start";while(true){//要接受客戶端的信息//ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr,  *addrlen);char inbuffer[1024];struct sockaddr_in peer;socklen_t len = sizeof(peer) ;ssize_t n = ::recvfrom ( _sockfd,inbuffer,sizeof(inbuffer)-1,0,CONV(&peer),&len);if(n>0){uint16_t clientport = ::ntohs(peer.sin_port);std::string clientip = ::inet_ntoa(peer.sin_addr);inbuffer[n] = 0;std::string clientinfo = clientip + ":" + std::to_string(clientport) + "#" + inbuffer;LOG(LogLevel::DEBUG) << clientinfo;//接受消息后 還有給客戶端發送數據std::string echo_string = "echo#" ; echo_string += inbuffer;::sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,CONV(&peer),len);}else{LOG(LogLevel::FATAL) << "recvfrom: " << strerror(errno);}}

我們再說一個轉換函數,這個要比inet_ntoa()函數轉換更加安全

_ip = ::inet_ntop(AF_INET, &_local.sin_addr, ipbuffer, sizeof(ipbuffer));

inet_ntoa 本質呢是在內部有一個靜態存儲區,如果是多線程調用它,很容易進行覆蓋,所以它并不安全,inet_ntop 這個函數是讓你自己申請一個靜態區,所以由程序員自己掌握,相對安全。

1.6 是否要綁定固定的 IP 和端口號

端口號有一定的定義范圍

IP地址的定義范圍


IPv4地址是一個32位的二進制數,通常被分為四段表示,每段8位,并以點分十進制(dotted-decimal notation)的形式表示,即每個字節轉換為對應的十進制數字,各字節間用點號隔開。范圍:0.0.0.0~255.255.255.255
特殊用途的IPv4地址范圍包括:
私有地址:這些地址范圍專門保留用于內部網絡,不會在全球互聯網路由中出現。10.0.0.0 ~?10.255.255.255? ? 172.16.0.0 ~?172.31.255.255? ? ?192.168.0.0 ~ 192.168.255.255
回環地址:用于本機回環測試,通常使用127.0.0.1代表本地主機。
127.0.0.0 到 127.255.255.255
自動專用IP尋址:當無法從DHCP服務器獲得配置時,系統可能會自動配置此范圍內的地址。
169.254.0.0 到 169.254.255.255。

我們要不要再服務器中,把某個進程也就是它的端口號,和IP綁定在一起呢

答案是,不要,因為一個公司里的服務器,會有很多的IP地址,我們要給同一個端口發送消息,那么經過不同的IP,同一個端口號,都能給這個進程發送信息,但是如果你綁定了特定的IP,那么只有通過這個IP,才能給這個進程發送消息,所以我們不能綁定IP。

1.7 客戶端

在我們學習完服務端之后,客戶端就很簡單了。

首先依舊是創建一個網絡通信的文件,和上面一樣。

然后區別來了:客戶端用不用綁定網絡信息呢??、

答案是:不用。為什么呢?難道客戶端發送不需要對方知道自己的網絡信息嗎?并不是這樣的,只是不用綁定,是因為系統回自動給客戶端自由隨機分配一個,為什呢?假設你的淘寶進程 你給綁定了80的端口號,而抖音也要這個端口號,那么不就起了沖突嗎?而讓系統自己分配,就可以避免這種沖突。只是不用手動綁定,而不是沒有網絡信息。

接著是一樣的發送消息,接受消息。

這個的設計思路是,直接默認手輸服務端的IP和端口,所以我們要用 argc 和 argv 兩個參數。

 if (argc != 3){std::cerr << "Usage: " << argv[0] << " localport" << std::endl;Die(USAGE_ERR);}ENABLE_CONSOLE_LOG();// ip + portstd::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){std::cerr << "socket error" << std::endl;Die(SOCKET_ERR);}struct sockaddr_in tmp;memset(&tmp, 0, sizeof(tmp));tmp.sin_family = AF_INET;tmp.sin_port=::htons(serverport);tmp.sin_addr.s_addr = inet_addr(serverip.c_str());while(true){std::cout<<"輸入你要說的話"<<std::endl;std::string tstring;std::getline(std::cin,tstring);int n = ::sendto(sockfd,tstring.c_str(),tstring.size(),0,CONV(&tmp),sizeof(tmp));if(n<0){LOG(LogLevel::FATAL)<<"Client send to false";}char inbuffer[1024];struct sockaddr_in server;socklen_t len = sizeof(server);int m = ::recvfrom(sockfd,inbuffer,sizeof(inbuffer)-1,0,CONV(&server),&len);if(m>0){inbuffer[m] = 0;std::cout<<inbuffer<<std::endl;}}

1.8 實現云平臺和云平臺直接的通信

那么你直接開兩個終端,一個運行客戶端,一個運行服務端,默認服務端 的端口號8080或者8888都可以。然后直接通信就可以了

1.9 云平臺和Windows 的通信

首先你要在你的云平臺的管理器那里,申請UDP通信,要保證你的UDP端口是可以用的。接下來給大家分享一個Windows端作為用戶端的代碼,云平臺依舊使用我們剛才的服務端的代碼就可以

#include <iostream>
#include <cstdio>
#include <thread>
#include <string>
#include <cstdlib>
#include <WinSock2.h>
#include <Windows.h>
#pragma warning(disable : 4996)
#pragma comment(lib, "ws2_32.lib")
std::string serverip = ""; //自己云平臺的IP
uint16_t serverport = 8080;//默認一個端口號就可以
int main()
{WSADATA wsd;WSAStartup(MAKEWORD(2, 2), &wsd);struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(serverport); //?server.sin_addr.s_addr = inet_addr(serverip.c_str());SOCKET sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd == SOCKET_ERROR){std::cout << "socker error" << std::endl;return 1;}std::string message;char buffer[1024];while (true){std::cout << "Please Enter@ ";std::getline(std::cin, message);if (message.empty()) continue;sendto(sockfd, message.c_str(), (int)message.size(), 0,(struct sockaddr*)&server, sizeof(server));struct sockaddr_in temp;int len = sizeof(temp);int s = recvfrom(sockfd, buffer, 1023, 0, (struct sockaddr*)&temp, &len);if (s > 0){buffer[s] = 0;std::cout << buffer << std::endl;}}closesocket(sockfd);WSACleanup();return 0;
}

網絡的代碼一樣,只是在Windows下,某些文件需要提前配置和打開關閉。

2.0奉上全部代碼

UDPClient.cc

#include<iostream>
#include "Log.hpp"
#include "UdpServer.hpp"
#include <string>
#include "Common.hpp"
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace LogModule;
int main(int argc, char *argv[])
{if (argc != 3){std::cerr << "Usage: " << argv[0] << " localport" << std::endl;Die(USAGE_ERR);}ENABLE_CONSOLE_LOG();// ip + portstd::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){std::cerr << "socket error" << std::endl;Die(SOCKET_ERR);}struct sockaddr_in tmp;memset(&tmp, 0, sizeof(tmp));tmp.sin_family = AF_INET;tmp.sin_port=::htons(serverport);tmp.sin_addr.s_addr = inet_addr(serverip.c_str());while(true){std::cout<<"輸入你要說的話"<<std::endl;std::string tstring;std::getline(std::cin,tstring);int n = ::sendto(sockfd,tstring.c_str(),tstring.size(),0,CONV(&tmp),sizeof(tmp));if(n<0){LOG(LogLevel::FATAL)<<"Client send to false";}char inbuffer[1024];struct sockaddr_in server;socklen_t len = sizeof(server);int m = ::recvfrom(sockfd,inbuffer,sizeof(inbuffer)-1,0,CONV(&server),&len);if(m>0){inbuffer[m] = 0;std::cout<<inbuffer<<std::endl;}}return 0;
}

UDPServer.hpp

#ifndef __UDP_SERVER_HPP__
#define __UDP_SERVER_HPP__#include <iostream>
#include <string>
#include <memory>
#include <cstring>
#include <cerrno>
#include <strings.h>#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#include "Log.hpp"
#include "Common.hpp"using namespace LogModule;const static  std::string fault_ip = "127.0.0.1";
const static  uint16_t fault_port = 8080;
class UDPServer
{
public:UDPServer(std::string ip = fault_ip, uint16_t port = fault_port): _ip(ip), _port(port), _isrunning(false), _sockfd(-1){}void InitServer(){_sockfd = socket(AF_INET, SOCK_DGRAM, 0); //這是創建好了一個網絡上的文件if (_sockfd < 0){LOG(LogLevel::FATAL) << "socket create false";Die(USAGE_ERR);}LOG(LogLevel::INFO) << "socket success, sockfd is : " << _sockfd;struct sockaddr_in local;bzero(&local, sizeof(local)); // 最好是先清零再去給它賦值 用memset也可以local.sin_family = AF_INET;local.sin_port = ::htons(_port); // 因為字節序的問題 ,最好是要給轉換成網絡的大端local.sin_addr.s_addr = inet_addr(_ip.c_str());//要綁定網絡上的信息  你要知道是誰傳的 ip + portint n = bind(_sockfd, CONV(&local), sizeof(local));if (n < 0){LOG(LogLevel::FATAL) << "bind: " << strerror(errno);Die(BIND_ERR);}LOG(LogLevel::INFO) << "bind success";}void Start(){LOG(LogLevel::INFO) << "start";_isrunning = true;while(true){//要接受客戶端的信息// ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,//                   struct sockaddr *src_addr,  *addrlen);char inbuffer[1024];struct sockaddr_in peer;socklen_t len = sizeof(peer) ;ssize_t n = ::recvfrom ( _sockfd,inbuffer,sizeof(inbuffer)-1,0,CONV(&peer),&len);if(n>0){uint16_t clientport = ::ntohs(peer.sin_port);std::string clientip = ::inet_ntoa(peer.sin_addr);inbuffer[n] = 0;std::string clientinfo = clientip + ":" + std::to_string(clientport) + "#" + inbuffer;LOG(LogLevel::DEBUG) << clientinfo;//接受消息后 還有給客戶端發送數據std::string echo_string = "echo#" ; echo_string += inbuffer;::sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,CONV(&peer),len);}else{LOG(LogLevel::FATAL) << "recvfrom: " << strerror(errno);}}}~UDPServer(){}private:int _sockfd; // 建立的網絡文件描述符std::string _ip;uint16_t _port;bool _isrunning;
};#endif

UDPServer.cc

#include<iostream>
#include "Log.hpp"
#include "UdpServer.hpp"
#include <string>
#include "Common.hpp"
using namespace LogModule;
int main(int argc, char *argv[])
{if (argc != 3){std::cerr << "Usage: " << argv[0] << " localport" << std::endl;Die(USAGE_ERR);}ENABLE_CONSOLE_LOG();std::string ip = argv[1];uint16_t port = std::stoi(argv[2]);std::unique_ptr<UDPServer> svr_uptr = std::make_unique<UDPServer>(ip,port);svr_uptr->InitServer();svr_uptr->Start();return 0;
}

Common.hpp

#pragma once#include <iostream>#define Die(code)   \do              \{               \exit(code); \} while (0)#define CONV(v) (struct sockaddr *)(v)enum 
{USAGE_ERR = 1,SOCKET_ERR,BIND_ERR
};

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

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

相關文章

AI - MCP 協議(一)

AI應用開發的高級特性——MCP模型上下文協議&#xff0c;打通AI與外部服務的邊界。 ************************************************************************************************************** 一、需求分析 當你的AI具備了RAG的能力&#xff0c;具備了調用工具的…

在es中安裝kibana

一 安裝 1.1 驗證訪問https的連通性 # 測試 80 端口&#xff08;HTTP&#xff09; curl -I -m 5 http://目標IP:端口號 說明&#xff1a; -I&#xff1a;僅獲取 HTTP 頭部&#xff08;Head 請求&#xff09;&#xff0c;不下載正文&#xff0c;減少數據傳輸。 -m 5&#x…

嵌入式開發學習———Linux環境下網絡編程學習(二)

UDP服務器客戶端搭建UDP服務器代碼#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h>#define PORT 8080 #define BUFFER_SIZE 1024int main() {int sockfd;char buffer[BUFFER_SIZE…

UVa1465/LA4841 Searchlights

UVa12345 UVa1465/LA4841 Searchlights題目鏈接題意輸入格式輸出格式分析AC 代碼題目鏈接 本題是2010年icpc亞洲區域賽杭州賽區的I題 題意 在一個 n 行 m 列&#xff08;n≤100&#xff0c;m≤10 000&#xff09;的網格中有一些探照燈&#xff0c;每個探照燈有一個最大亮度 k&…

詳解區塊鏈技術及主流區塊鏈框架對比

文章目錄一、區塊鏈技術棧詳解二、主流區塊鏈框架對比1. 公有鏈&#xff08;Public Blockchain&#xff09;2. 聯盟鏈&#xff08;Consortium Blockchain&#xff09;3. 私有鏈&#xff08;Private Blockchain&#xff09;三、技術選型建議1. 按需求選擇框架2. 開發工具與生態四…

大模型 + 垂直場景:搜索 / 推薦 / 營銷 / 客服領域開發有哪些新玩法?

技術文章大綱&#xff1a;大模型 垂直場景的新玩法大模型與搜索領域的結合大模型在搜索領域的應用可以顯著提升搜索結果的準確性和用戶體驗。利用大模型進行語義理解和上下文關聯&#xff0c;能夠實現更精準的意圖識別。結合知識圖譜和動態索引優化&#xff0c;可以增強長尾查…

p5.js 3D盒子的基礎用法

點贊 關注 收藏 學會了 如果你剛接觸 p5.js&#xff0c;想嘗試 3D 繪圖&#xff0c;那么box()函數絕對是你的入門首選。它能快速繪制出 3D 長方體&#xff08;或正方體&#xff09;&#xff0c;配合簡單的交互就能做出酷炫的 3D 效果。本文會從基礎到進階&#xff0c;帶你吃…

【動態規劃 完全背包 卡常】P9743 「KDOI-06-J」旅行|普及+

本文涉及知識點 C動態規劃 完全背包 C記憶化搜索 「KDOI-06-J」旅行 題目描述 小 C 在 C 國旅行。 C 國有 nmn\times mnm 個城市&#xff0c;可以看做 nmn\times mnm 的網格。定義 (i,j)(i,j)(i,j) 表示在網格中第 iii 行第 jjj 列的城市。 該國有 222 種交通系統&#x…

pytest框架-詳解

目錄 一、前言 二、pytest安裝 2.1、安裝 2.2、驗證安裝 2.3、pytest文檔 三、pytest框架的約束 3.1、 python的命名規則 3.2、 pytest的命名規則 四、pytest的運行方式 4.1、主函數運行 4.2、命令行運行 五、pytest配置文件pytest.ini文件 六、前置和后置 七、as…

【遞歸、搜索與回溯算法】DFS解決FloodFill算法

FloodFill算法簡介一、[圖像渲染](https://leetcode.cn/problems/flood-fill/description/)二、[島嶼數量](https://leetcode.cn/problems/number-of-islands/description/)三、[島嶼的最大面積](https://leetcode.cn/problems/max-area-of-island/description/)四、[被圍繞的區…

解決網絡傳輸中可能出現的“粘包”

先理解核心問題&#xff1a;什么是“TCP粘包”&#xff1f; TCP 就像一條水管&#xff0c;數據通過水管從一端傳到另一端。但它有個特點&#xff1a;不會按“發送時的小包”來劃分&#xff0c;而是把數據當成連續的字節流。 比如&#xff1a; 你分兩次發數據&#xff1a;第一次…

Docker搭建RSS訂閱服務(freshRss+rsshub)

目錄搭建freshRss1. 創建yml文件2. 創建容器3. 檢查容器狀態&#xff0c;正常運行則搭建成功4. 瀏覽器訪問并配置數據庫5. 開始使用搭建RssHub1. 創建yml文件2. 創建容器3. 檢查容器狀態&#xff0c;正常運行則搭建成功4. 瀏覽器訪問生成RSS路由&#xff08;訂閱地址&#xff0…

Spring 條件注解與 SPI 機制(深度解析)

在 Spring 及 Spring Boot 框架中&#xff0c;條件注解與 SPI 機制扮演著至關重要的角色&#xff0c;它們是實現自動配置、靈活控制 Bean 創建以及組件按需加載的關鍵所在。深入理解它們的底層實現與應用場景&#xff0c;既能幫助我們在面試中對答如流&#xff0c;又能在實際開…

Mac(二)Homebrew 的安裝和使用

官網地址&#xff1a; https://brew.sh/官方文檔&#xff1a; https://docs.brew.sh/Manpage Homebrew 是 macOS 上最強大的包管理器&#xff0c;讓你輕松安裝、更新和管理成千上萬的開發工具、命令行程序&#xff08;如 wget, tree, ffmpeg&#xff09;甚至圖形應用&#xff0…

Vue 偵聽器(watch 與 watchEffect)全解析2

二、watchEffect:自動追蹤依賴的偵聽器 watchEffect 是更“簡潔”的偵聽器:它不需要手動指定數據源,而是自動追蹤回調中用到的響應式狀態——當這些狀態變化時,自動觸發回調。適用于“副作用與依賴綁定緊密”的場景(如依賴較多、無需區分新舊值)。 1. 基本用法(與 wat…

正點原子STM32H743配置 LTDC + DMA2D

開發板 正點原子STM32H743 阿波羅固件包 STM32Cube MCU Package for STM32H7 1.12.1開發工具 STM32CubeMX STM32CubeIDE根據原理圖適配所有GPIO&#xff0c;并設置所有GPIO速度 Very Hight

北京JAVA基礎面試30天打卡10

1.最佳左前綴原則是什么 Q:什么是MySQL索引I的最左匹配原則&#xff1f; A:最左匹配原則是指&#xff0c;在復合索引引中&#xff0c;查詢條件需要按照索引列的順序從最左側列開始依次匹配。只有查詢條件中的列按照索引的最左邊列開始進行匹配,索引引才能被有效使用。 Q:能否舉…

五、ZooKeeper、Kafka、Hadoop、HBase、Spark、Flink集群化軟件的部署

五、ZooKeeper、Kafka、Hadoop、HBase、Spark、Flink集群化軟件的部署 文章目錄五、ZooKeeper、Kafka、Hadoop、HBase、Spark、Flink集群化軟件的部署1.作用主要作用&#xff08;通俗說法&#xff09;對實戰項目有什么用&#xff1f;&#xff08;直接舉例&#xff09;2.集群化軟…

下載及交叉編譯glib,記錄

下載及交叉編譯glib&#xff0c;記錄 編譯參見這篇博客 嵌入式arm交叉編譯移植bluez5.0最新教程_bluez移植-CSDN博客 編譯命令有更新&#xff1a; make -j4 CFLAGS"-Wno-format-overflow" glib庫的作用&#xff1a; glib 是 GNOME 項目下的一個基礎庫&#xff0c…

從 0 到 1 玩轉Claude code(藍耘UI界面版本):AI 編程助手的服務器部署與實戰指南

前言 藍耘 Coding UI 作為基于 Claude Code 的可視化工具&#xff0c;憑借對本地項目的深度掌控、與 Git 倉庫的無縫銜接以及直觀的交互界面&#xff0c;正在重構開發者的工作流。本文將帶你一步步完成從環境搭建到實戰使用的全流程&#xff0c;讓這款工具真正成為你的編程「副…