主頁 > 軟體設計 > 網路通信Socket(Linux)

網路通信Socket(Linux)

2021-11-13 20:49:37 軟體設計



網路通信之套接字Socket

預備知識根據自身基礎選擇性查看

文章目錄

  • 網路通信之套接字Socket
    • 預備知識:
      • IP 及 埠
      • 網路模型
      • 位元組序
      • IP地址轉換
      • 虛擬地址空間
      • 檔案描述符
      • sockaddr結構體 / sockaddr_in
    • socket 編程
      • TCP通信流程
      • socket常用函式詳解
      • 服務器端代碼實作
      • 客戶端代碼實作

預備知識:

IP 及 埠

IP: 本質為一個整型數,表示計算機在網路中的地址,IP協議有兩個:IPv4 和 IPv6

? IPv4協議:(目前用的最多)32位整型數表示,4個位元組 ,也可使用點分十進制描述: 192.168.255.65

? IPv4可是使用的最大地址有 2^32個,數量較少所有開始發展IPv6

? IPv6協議:128位整型數表示,16位元組,

? 使用字串描述IP地址 :2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b

? *IPv4可是使用的最大地址有 2^128個

埠 : 用于定位到主機上的某一個行程 ,通過這個埠行程進行通信

埠是一個無符號短整型(unsigned short),有效埠(0 ~ 2^16 -1)

注意:一個埠只能給一個行程使用

簡單理解: IP地址理解為 酒店的地址,埠理解為 具體房間的通信電話號碼

網路模型

網路分成模型

在這里插入圖片描述

網路各層的作用:

  1. 物理層: 負責最后將資訊編碼成電流脈沖或其他信號用于傳輸
  2. 資料鏈路層: 通過物理網路提供資料傳輸,確定網路資料包形式
  3. 網路層: 負責源和終點之間連接(通過 IPv4 或 IPv6 查找對應主機)
  4. 傳輸層 : 向高層提供端對端的網路資料流服務 (TCP / UDP 協議)
  5. 會話層 : 會話層建立、管理、終止表示層與物體之間的通信會話
  6. 表示層: 對應用層資料編碼和轉化,確保另一個應用層識別

位元組序

各計算機體系結構中,對存盤機制有所不用,為了正常通信,雙方應同一規則避免通信失敗,

顧名思義位元組的順序,就是大于一個位元組型別的資料在記憶體中的存放順序,也就是說對于單字符來說是沒有位元組序問題的,字串是單字符的集合,因此字串也沒有位元組序問題,

目前主要兩種位元組存盤機制:大端 、小端

  • 大端 :低位位元組存盤到記憶體的高地址位高位元組存盤到記憶體低地址位

? 其中網路通信使用大端存盤

  • 小端:低位位元組存盤到記憶體的低地址位高位元組存盤到記憶體高地址位

? 平時主機使用小端存盤

示例:

// 有一個16進制的數, 有32位 (int): 0xab5c01ff
// 位元組序, 最小的單位: char 位元組, int 有4個位元組, 需要將其拆分為4份
// 一個位元組 unsigned char, 最大值是 255(十進制) ==> ff(16進制) 
                 記憶體低地址位                記憶體的高地址位
--------------------------------------------------------------------------->
小端:         0xff        0x01        0x5c        0xab
大端:         0xab        0x5c        0x01        0xff

Socket提供好了封裝介面,用與在主機 ->網路 -> 主機之間轉換位元組序的函式 主->網(htons \ htonl) // 網->z主(ntohs\ntohl)

//主機位元組序 ->  網路位元組序    (短整型)
uint16_t  htons(uint16_t hostshort);
//主機位元組序 ->  網路位元組序    (長整型)
uint32_t  htonl(uint16_t hostlong);

//網路位元組序 -> 主機位元組序 (短整型)
uint16_t ntohs(uint16_t netshort);
//網路位元組序 ->  主機位元組序    (長整型)
uint32_t  ntohl(uint16_t hostlong);

注意:在傳輸資料時,記得轉換位元組序

IP地址轉換

雖然IP的本質是整型資料,但是使用程序中通常通過字串描述

IP地址使用時也需要轉換大小端

//主機位元組序  -> 網路位元組序
//主機位元組序的IP地址為 字串 , 網路位元組序的IP地址為整型
int inet_pton(int af, const char* src , void* dst);

//引數
af :地址族協議   (IPv4協議 : AF_INET) (IPv6協議: AF_INET6)
src: 輸入引數,(點分十進制) 192.168.255.45
dst: 輸出引數 , (大端整型)

//大端整型 ->小端點分十進制IP地址
const char* inet_ntop(int af , const char* src , char *dest , socklen_t size);

//引數
af :地址族協議   (IPv4協議 : AF_INET) (IPv6協議: AF_INET6)
src: 輸入引數,(大端整型)
dst: 輸出引數 , (點分十進制) 192.168.255.45
size: 標記dst指向記憶體最多儲存多少位元組

虛擬地址空間

虛擬地址空間 :作業系統知識補充

當我們運行磁盤上的一段可執行程式,就會得到一個行程(行程是一段程式的執行程序,是動態概念) ,內核會給每一個運行的行程分配一塊屬于自己的虛擬地址空間,并將應用程式資料裝載在對應的虛擬記憶體地址上,

行程運行程序中處理的資料從物理記憶體中加載,行程中的資料通過CPU的記憶體管理單元從虛擬地址空間中映射過去,

在這里插入圖片描述

虛擬地址的意義

為什么作業系統不直接從物理記憶體上獲取資料?如果直接讀取會發生什么?

在這里插入圖片描述

行程A需要100m記憶體 ,直接在物理記憶體上從0地址開始分配置100 , 同理行程B分配250m記憶體,并且行程A和行程B占用的記憶體為連續的,會發生如下問題:

  1. 每個行程的地址不隔離,有安全風險:程式直接訪問物理記憶體可能存在bug的程式修改其他程式的記憶體結構
  2. 記憶體效率低: 直接物理記憶體,行程對應整塊記憶體,如果記憶體不足時資料量大,記憶體和磁盤拷貝時間會很長,效率低
  3. 行程中資料的地址不確定,每次都會有變化: 物理記憶體使用是動態的,無法確定記憶體使用情況,起始地址都不同,加載資料效率低

檔案描述符

檔案描述符

在Linux系統中,一切皆是檔案,如何將應用程式和檔案對應?

解決方案是使用檔案描述符(fd),當在行程中打開一個現有檔案或創建一個新檔案時,內核會向行程回傳一個檔案描述符用于對應這個打開/新建的檔案,這些檔案描述符存盤在內核為維護行程的一個檔案描述符表中,

檔案描述符的概念往往只適用于 Linux 或 Unix 系統

檔案描述符表

前面講到啟動一個行程就會得到一個對應的虛擬地址空間,這個虛擬地址空間分為兩大部分,Linux 的行程控制塊 PCB (pcb簡單理解為一個行程所有基本資訊),里邊包括管理行程所需的各種資訊,其中有一個結構體叫做 file ,我們將它叫做檔案描述符表里邊有一個整形索引表,用于存盤檔案描述符

在這里插入圖片描述

檔案描述符表性質 1: 每個行程對應的檔案描述符表默認支持打開的最大檔案數為 1024,可以修改
檔案描述符表性質 2: 每個行程的檔案描述符表中都已經默認分配了三個檔案描述符,對應的都是當前終端檔案
檔案描述符表性質3:.每打開新的檔案,內核會從行程的檔案描述符表中找到一個空閑的沒有別占用的檔案描述符與其進行關聯
檔案描述符表性質4 : 每個行程檔案描述符表中的檔案描述符值是唯一的,不會重復

sockaddr結構體 / sockaddr_in

struct sockaddr 是一個通用地址結構 , 是為了同一地址結構的表示方式,統一介面函式,使不同的地址結構可以被 bind() —connect() 等函式呼叫;

sockaddr 結構體的缺陷 : sa_data把目標地址和埠資訊混在一起了

struct sockaddr{
  unsigned short sa_family;
  char sa_data[14];
};
  1. sa_family : 通信型別,地址族協議(IPv4/IPv6)
  2. sa_data : 14位元組 ,包含套接字中的 目標地址 和 埠資訊

sockaddr_in 結構體:struct sockaddr_in中的in 表示internet,就是網路地址,這只是我們比較常用的地址結構,屬于AF_INET地址族
sockaddr_in結構體解決了sockaddr的缺陷,把port和addr 分開儲存在兩個變數中

struct in_addr{
  unsigned long s_addr;
}

struct sockaddr_in {
  short int sinfamily;
  unsigned short int sin_port ;
  struct in_addr sin_addr;
  unsigned char sin_zero[8];
}

sin_port / s_addr 一般為主機位元組序(小端),使用時注意初始化轉化為網路位元組序(htons()函式)

使用方式

一般先把sockaddr_in 變數賦值后 ,強制轉換后傳入用于sockaddr做引數

  1. sockaddr_in 用于socked 定義和賦值
  2. sockaddr 用于函式引數

socket 編程

為了將TCP/IP 協議相關軟體移植UNIX類系統中,設計者開發一個介面以便于應用程式能簡單的呼叫介面通信,最終形成了Socket套接字,Linux系統采用套接字通信,因此廣泛使用,其頭檔案包含在 sys/socket.h中

TCP通信流程

TCP是一個 面向連接(雙向連接)安全(資料校驗)流式傳輸(發送/接受資料速度,資料量可以不一致)傳輸層協議

在這里插入圖片描述

服務器端通信流程

//創建用于監聽的套接字 ,這個套接字是一個檔案描述符
int lfd = socket();

//系結 監聽的檔案描述符 的 IP地址 和 埠號
bind();

//設定監聽是否有客戶端發起連接請求
listen();

//等待客戶端連接 ,當有客戶端連且請求會創建用于通信的檔案描述符 ,沒有連接便阻塞
int cfd = accept();

//通信 :讀、寫 默認都是阻塞的
write();   //send();
read();   //recv();

//斷開連接 、 關閉套接字
close();

注意:服務器端有兩種檔案描述符,一類是用于監聽客戶端連接請求(只存在一個),檢測到連接請求后會呼叫accept創建新連接, 另一類檔案描述符用于和客戶端通信(N個),每個客戶端和服務器都對應一個通信的檔案描述符 簡化理解:服務器檔案描述符 (用于監聽客戶端連接)、(用于和已連接客戶端通信)

此處檔案描述符記憶體結構

在這里插入圖片描述

對應兩塊記憶體: 讀緩沖區 、 寫緩沖區

讀緩沖區 :通過檔案描述符將記憶體中的資料讀出

寫緩沖區 :通過檔案描述符將資料寫入記憶體中

客戶端通信流程

單執行緒情況下,只有一個通信的檔案描述符

//創建一個通信的套接字
int cfd = socket();

//連接服務器 ,需要知道 IP地址 和 埠號
connect();

//通信 :讀、寫 
write();   //send();
read();  //recv();

//斷開連接 ,關閉套接字(檔案描述符)
close();

socket常用函式詳解

//創建一個套接字
int socked(int domain ,int type ,int protocol);  //創建失敗 回傳 -1

domain : 使用的地址族協議(IPv4 、IPv6)

  • IPv4 :AF_INET
  • IPv6 :AF_INET6

type: 傳輸方式 (流式 、報式)

  • SOCK_STREAM: 使用流式的傳輸協議
  • SOCK_DGRAM: 使用報式 (報文) 的傳輸協議

protocol : 默認 0

  • 選擇流式傳輸 使用TCP
  • 選擇報式傳輸 使用UDP
//系結用于監聽檔案描述符  IP 、埠
int bind(int sockfd , const struct sockaddr* addr , socklen_t  addrlen);  //創建失敗 回傳 -1
  • sockfd: 監聽的檔案描述符,通過 socket () 呼叫得到的回傳值
  • addr: 傳入引數,要系結的 IP 和埠資訊需要初始化到這個結構體中,IP和埠要轉換為網路位元組序
  • addrlen: 引數 addr 指向的記憶體大小,sizeof (struct sockaddr)
//給監聽的套接字設定監聽
int listen(int sockfd ,int backlog);  //創建失敗 回傳 -1
  • sockfd: 檔案描述符,可以通過呼叫 socket () 得到,在監聽之前必須要系結 bind ()
  • backlog: 同時能處理的最大連接要求,最大值為 128
//等待并接受客戶端的連接,如果或連接請求創建新的用于通信的套接字 ,沒有連接便會阻塞
int accept(int sockfd , struct sockaddr *addr ,socklen_t *addrlen);  //成功回傳檔案描述符,失敗 -1
  • sockfd: 監聽的檔案描述符
  • addr: 傳出引數,里邊存盤了建立連接的客戶端的地址資訊
  • addrlen: 傳入傳出引數,用于存盤 addr 指向的記憶體大小

這個函式是一個阻塞函式,當沒有新的客戶端連接請求的時候,該函式阻塞;當檢測到有新的客戶端連接請求時,阻塞解除,新連接就建立了,得到的回傳值也是一個檔案描述符,基于這個檔案描述符就可以和客戶端通信了

//接受資料
ssize_t read(int socket , void* buf,size_t len);    //失敗 -1

//發送資料
ssize_t write(int socket , void* buf,size_t len);     //失敗 -1
  • fd: 通信的檔案描述符,accept () 函式的回傳值
  • buf: 傳入引數,要發送的字串
  • len: 要發送的字串的長度
//成功連接后,客戶端隨機系結一個埠
//服務器端呼叫 accept() ,其中第二個引數存盤客戶端 IP \埠
int connect(int sockfd ,struct sockaddr *addr ,socklen_t *addrlen);  //成功回傳 0,失敗 -1

服務器端代碼實作

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>


int main()
{
	//創建用于監聽的套接字
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	if (fd == -1)
	{
		perror("socket() fail");
		return -1;
	}

	//系結本地ip port
	//使用sockaddr_in 初始化避免IP和埠混亂
	struct sockaddr_in saddr;  
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(8888);//轉化為網路位元組序
	saddr.sin_addr.s_addr = INADDR_ANY; // 0 = 0.0.0.0 對于0,沒有大小端差別

	//使用時在強轉為sockaddr型別
	int ret = bind(fd, (struct sockaddr*)&saddr, sizeof(saddr));
	if (ret == -1)
	{
		perror("bind() fail");
		return -1;
	}

	//設定監聽
	ret = listen(fd, 128);
	if (ret == -1)
	{
		perror("listen() fail");
		return -1;
	}

	//阻塞并等待客戶端的連接
	struct sockaddr_in caddr;
	int addrlen = sizeof(caddr);
	int cfd = accept(fd, (struct sockaddr*)&caddr, &addrlen);
	if (cfd == -1)
	{
		perror("accept() fail");
		return -1;
	}

	//新連接成功,列印客戶端的 IP 和 Port 資訊
	char ip[32];
	printf("客戶端的 IP :%s  Port :%d \n",
		inet_ntop(AF_INET, &caddr.sin_addr.s_addr, ip, sizeof(ip)),
		ntohs(caddr.sin_port));

	//通信
	while (1)
	{
		//接受客戶端資料
		char buff[1024];
		int len = recv(cfd, buff, sizeof(buff), 0);
		if (len > 0) {
			printf("client say :%s", buff);
			send(cfd, buff, len, 0);//發送訊息給客戶端
		} 
		else if (len == 0)
		{
			printf("客戶端已經斷開連接");
			break;
		}
		else
		{
			perror("recv() fail");
			break;
		}
	}
	//關閉檔案描述符(兩類)
	close(fd);
	close(cfd);

	return 0;
}

客戶端代碼實作

// client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>

int main()
{
    // 1. 創建通信的套接字
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd == -1)
    {
        perror("socket");
        exit(0);
    }

    // 2. 連接服務器
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(10000);   // 大端埠
    inet_pton(AF_INET, "192.168.110.138 ", &addr.sin_addr.s_addr);

    int ret = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
    if (ret == -1)
    {
        perror("connect");
        exit(0);
    }

    // 3. 和服務器端通信
    int number = 0;
    while (1)
    {
        // 發送資料
        char buf[1024];
        sprintf(buf, "你好, 服務器...%d\n", number++);
        write(fd, buf, strlen(buf) + 1);

        // 接收資料
        memset(buf, 0, sizeof(buf));
        int len = read(fd, buf, sizeof(buf));
        if (len > 0)
        {
            printf("服務器say: %s\n", buf);
        }
        else if (len == 0)
        {
            printf("服務器斷開了連接...\n");
            break;
        }
        else
        {
            perror("read");
            break;
        }
        sleep(1);   // 每隔1s發送一條資料
    }

    close(fd);

    return 0;
}

推薦大家多了解一些底層知識
推薦大丙老師的教程

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/356775.html

標籤:其他

上一篇:阿里云部署nginx

下一篇:華為網路配置(DHCP)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more