萬物互聯之~網路編程上篇

来源:https://www.cnblogs.com/dotnetcrazy/archive/2018/11/06/9919202.html
-Advertisement-
Play Games

入門篇¶ 官方文檔:https://docs.python.org/3/library/ipc.html(進程間通信和網路) 實例代碼:https://github.com/lotapp/BaseCode/tree/master/python/6.net 1.概念¶ 1.1.Python方向¶ 已經 ...


 

入門篇

官方文檔:https://docs.python.org/3/library/ipc.html(進程間通信和網路)

實例代碼:https://github.com/lotapp/BaseCode/tree/master/python/6.net

1.概念

1.1.Python方向

已經講了很多Python的知識了,那Python能幹啥呢?這個是我眼中的Python

Python方向

  1. 早期方向
    • Web全棧
  2. 擅長專欄
    • 爬蟲系列
    • 數據分析
    • 人工智慧
    • 物聯網系lot萬物互聯)
    • 自動化運維安全測試
  3. 其他系列
    • 游戲開發(最近很火)

如果想專攻Web爬蟲物聯網游戲等等方向,網路這塊是硬條件,So ==> 不要不急,咱們繼續學習~

多句嘴,一般情況下需要什麼庫就去官方看下,沒有再考慮第三方:https://docs.python.org/3/library

1.2.拙見一點點

技術前景:(註意加粗方向)

  1. Python
    1. 最常用:Data
    2. 最看好:LoT
    3. 最火是:AI
    4. 經典是:Web
    5. 壟斷是:System
  2. Web
    1. 最看好:小程式
    2. 最常見:移動端
    3. 最火是:Web端
  3. Go高併發區塊鏈)、C(基礎
  4. NetCoreWebAPIEFCore

總的來說:Python最吃香,Go最有潛力,Web必不可少,NetCore性價比高

現在基本沒有單一方向的程式員了,如果有可以默默思考幾分鐘,一般都是JS and Python and (Go or NetCore)【二選一】


其他行業:(僅代表逆天個人看法

  1. 設計師
    1. 影視製作(剪輯師、合成師、特效師)【目前最火,性價比很高】
    2. 修圖師(商業修片、影樓後期)【大咖特別多,創業很吃香】
    3. UI|UE(最容易找工作)
    4. 平面設計(最常見)
    5. 室內設計(高手很吃香)
  2. 教育
    1. 幼兒編程中醫課最火
    2. 琴棋書畫武+國學需求頗高
    3. 英語一直是出國必學
  3. 營銷新媒體+短視頻
  4. 旅游出國游

1.2.分層模型

1.OSI 7層模型

  1. 物理層:物理設備標準,主要作用就是傳輸比特流(數據為bit)eg:網線介面、光纖介面、各種傳輸介質的傳輸速率
    • 雙絞線,光纖(硬體)
  2. 數據鏈路層:對物理層的校驗(是否有丟失、錯誤)
    • 數據的傳輸和數據檢測(網卡層)
  3. 網路層:指定傳輸過程中的路徑。eg:IP
    • 為數據包選擇路由(保證數據傳達)
  4. 傳輸層:定義了傳輸數據的協議和埠號(主要就是攜帶了埠號,這樣可以找到對應的進程)
    • 提供端對端的介面,eg:TCP、UDP
  5. 會話層:通過傳輸層,在端與端之間(埠)建立數據傳輸通道(設備之間可以通過IP、Mac、主機名相互認識)
    • 解除或者建立和別的節點之間的聯繫
  6. 表示層:保證一個系統應用發的消息可以被另一個系統應用讀取到。eg:兩個應用發送的消息格式不同(eg:UTF和ASCII各自表示同一字元),有必要時會以一種通用格式來實現不同數據格式之間的轉換
    • 數據格式化、代碼轉化、數據加密
  7. 應用層:為用戶的應用程式提供網路服務
    • 文件傳輸、電子郵箱、文件服務、虛擬終端

我用PPT畫了個圖:( ) 1.分層模型.png

2.TCP/IP 4層模型

  1. 網路介面層:(物、數
    • eg:乙太網幀協議
  2. 網路層
    • eg:IP、ARP協議
  3. 傳輸層
    • eg:TCP、UDP協議
  4. 應用層:(會、表、應)我們基本上都是關註這個
    • eg:FTP、SSH、HTTP協議...

1.3.協議相關

電腦和電腦網路通信前達成的一種約定,舉個例子:以漢語為交流語言 1.協議定義.png

再舉個發送文件的例子,PPT做個動畫:(自定義協議-文件傳輸演示) 1.文件傳輸演示.gif

B/S基本上都是HTTP協議,C/S開發的時候有時會使用自己的協議,比如某大型游戲,比如很多框架都有自己的協議:

  1. Redis的redis://
  2. Dubbo的dubbo://協議

總的來說,基本上都是HTTP協議,對性能要求高的就使用TCP協議,更高性能要求就自己封裝協議了,比如騰訊在UDP基礎上封裝了自己的協議來保證通信的可靠性

數據包的封裝

先看一個老外的動畫(忽略水印廣告):https://v.qq.com/x/page/w01984zbrmy.html

中文版可以點擊微信公眾號的原文鏈接下載(課外拓展也有貼)

以TCP/IP四層協議為例:數據包的逐層封裝解包都是操作系統來做的,我們只管應用層

發送過程:

  1. 發送消息
  2. 應用層添加了協議頭
  3. 傳輸層添加TCP段首
  4. 網路層添加IP報頭
  5. 網路介面層(鏈路層)添加幀頭幀尾

PPT動畫示意: 1.傳輸.gif

接收過程:

  1. 去除鏈路層的幀頭幀尾
  2. 去除網路層IP報頭
  3. 去除傳輸層TCP段首
  4. 去除應用層的協議頭
  5. 獲取到數據

PPT動畫示意: 2.解包.gif

我們下麵按照解包順序簡單說說各種格式

1.乙太網幀格式

先看一下這個是啥?用上面動畫內容表示: 1.乙太網幀格式是啥.png

乙太網幀協議根據MAC地址完成數據包傳遞

如果只知道IP,並不知道MAC地址,可以使用ARP請求來獲取:

  • ARP數據報:根據IP獲取MAC地址(網卡編號)
  • ARP只適合IPv4,IPv6ICMPV6來代替ARP
  • TCP/IP模型中,ARP協議屬於IP層;在OSI模型中,ARP協議屬於鏈路層

PPT畫一張圖:1bit = 8byte(1位元組=8位) 1.乙太網幀格式.png

上圖數據最小46位元組,而ARP就28位元組,所以需要填充(PAD)18個無用位元組

課後思考:根據ARP原理想想ARP欺騙到底扎回事?(IP進行ARP請求後會緩存,緩存失效前不會再去ARP請求)

擴展:

  1. RARP 是反向地址轉換協議,通過 MAC 地址確定 IP 地址
  2. 真實IP在網路層的IP協議之中,乙太網幀中的IP是下一跳的IP地址(路由)
  3. 每到一個路由都要解網路層的包(知道到底需要獲取哪個IP)
  4. MAC地址就是硬體地址,廠商向全球組織申請唯一編號(類似於身份證)
  5. 最後附上手畫的ARP數據報圖示:(一般都不是一步得到MAC的,多數都是經過一個個路由節點最終獲取到MAC)

1.ARP.png

2.IP段格式

先貼一IP段格式圖片(網路): 1.IP報.png

我們在這不去詳細講解,擴展部分有課後拓展,我就說一個大多數人困惑的點:

查看IP信息的時候經常會看到192.168.36.235/24,這個/24一直爭議很大

我們來簡單解釋一下:IP為192.168.36.235

  1. 192.168.36:網路標識
  2. 235:主機標識
  3. /24標識從頭數到多少位為止屬於網路標識(剩下的就是可分配的主機數了)
    • 二進位表示為:11111111 11111111 11111111 00000000(24個1)
    • 翻譯成子網掩碼就是:255.255.255.0(/多少就數多少個1,然後轉化)
    • 表示可以有255個ip用來自行分配(記得去除路由之類的占用)

擴展:IP屬於面向無連接行(IP協議不保證傳輸的可靠性,數據包在傳輸過程中可能丟失,可靠性可以在上層協議或應用程式中提供支持)

面向連接面向無連接區別如圖:(圖片來自網路1.面向有無連接.png


預告

關於TCP和UDP的內容下次繼續~

課外拓展:

圖解TCP/IP第五版
鏈接: https://pan.baidu.com/s/1C4kpNd2MvljxfwTKO082lw 提取碼: 7qce

Python網路編程第三版
Code:https://github.com/brandon-rhodes/fopnp
PDF:鏈接: https://pan.baidu.com/s/1jhW-Te-GCEFKrZVf46S_Tw 提取碼: d7fw

網路基礎-含書簽(網路文檔)
鏈接: https://pan.baidu.com/s/1WZ1D4BthA4qBk2QXBAjm4w 提取碼: jmdg

老外講解網路數據包解析:
下載:https://pan.baidu.com/s/1uUjahs_b05y9Re9ROtzzIw
中文:http://video.tudou.com/v/XMjE3MTg0NzkzNg==.html
英文:http://video.tudou.com/v/XMTkyNjU5NDYwOA==.html
 

2.UDP

實例代碼:https://github.com/lotapp/BaseCode/tree/master/python/6.net/1.UDP

UDP是無連接的傳輸協議,不保證可靠性。使用UDP協議的應用程式需要自己完成丟包重發、消息排序等工作(有點像寄信)

2.1.UDP發送消息

引入案例

看個UDP的簡單案例:

import socket

def main():

    # AF_INET ==> IPV4;SOCK_STREAM ==> 類型是TCP,stream 流
    # SOCK_DGRAM ==> 類型是UDP,dgram 數據報、數據報套接字
    with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as udp_sock:
        udp_sock.sendto("大兄弟,你好啊".encode("utf-8"), ("192.168.36.235", 8080))
    print("over")

if __name__ == '__main__':
    main()

接收到的消息:這時候埠是隨機的 2.UDP接收消息

看起來代碼還挺麻煩,我稍微分析下你就知道對比其他語言真的太簡單了:

標識:

  1. AF_INET ==> IPV4
  2. SOCK_DGRAM ==> 類型是UDP
  3. SOCK_STREAM ==> 類型是TCP

代碼三步走

  1. 創建 udp_sock=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  2. 發送 udp_sock.sendto(Bytes內容,(IP,Port)) 接收:udp_sock.recvfrom(count)
  3. 關閉 udp_sock.close()

埠綁定

藉助調試工具(點我下載)可以知道:上面程式每次運行,不固定 2.UDP隨機埠.png

那怎麼使用固定埠呢?==> udp_socket.bind(('', 5400))

import socket

def main():
    with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as udp_socket:
        # 綁定固定埠
        udp_socket.bind(('', 5400))
        # 發送消息
        udp_socket.sendto("小明,你知道小張的生日嗎?\n".encode("utf-8"),
                          ("192.168.36.235", 8080))
    print("over")

if __name__ == '__main__':
    main()

消息圖示:nc -ul 8080nc -l是監聽TCP) 2.nc監聽UDP.png

調試工具: 2.UDP綁定埠.png

2.2.UDP接收消息

先看一個簡單版本的:udp_socket.recvfrom(1024)

from socket import socket, AF_INET, SOCK_DGRAM

def main():
    with socket(AF_INET, SOCK_DGRAM) as udp_socket:
        # 綁定埠
        udp_socket.bind(('', 5400))
        while True:
            # 發送消息
            udp_socket.sendto("你可以給我離線留言了\n".encode("utf-8"),
                              ("192.168.36.235", 8080))
            # 接收消息(data,(ip,port))
            data, info = udp_socket.recvfrom(1024)
            print(f"[來自{info[0]}:{info[1]}的消息]:\n{data.decode('utf-8')}")

if __name__ == '__main__':
    main()

圖示:接收消息(data,(ip,port)) 2.udp_recv.gif


題外話(Nmap)

其實如果你使用Nmap來掃描的話並不能發現nc打開的UDP埠: 2.nmap的UDP掃描.gif

稍微解釋一下:掃描其實就是發了幾個空消息過去

  1. -sU代表掃描UDP,-sT代表掃描TCP
  2. -Pn 這個主要是針對有些伺服器禁用ping的處理(ping不通也嘗試)
  3. -p 指定埠號,如果是所有埠可以使用-p-
  4. sudo是因為在Ubuntu下沒許可權,kali下可以直接使用nmap

可能有人對nc輸出的你可以給離線留意了有疑惑,其實就是在給5400埠發空消息的時候~True迴圈了兩次

來張對比圖: 2.nc找不到.gif

掃描TCP和UDP埠sudo nmap -sTU 192.168.36.235 -Pn

課後擴展

NC命令擴展:https://www.cnblogs.com/nmap/p/6148306.html

Nmap基礎:https://www.cnblogs.com/dunitian/p/5074784.html

收放自如

如果還是用True迴圈來實現:

from socket import socket, AF_INET, SOCK_DGRAM

def main():
    with socket(AF_INET, SOCK_DGRAM) as udp_socket:
        # 綁定埠
        udp_socket.bind(('', 5400))
        while True:
            msg = input("請輸入發送的內容:")
            if msg == "dotnetcrazy":
                break
            else:
                udp_socket.sendto(
                    msg.encode("utf-8"), ("192.168.36.235", 8080))

            data, info = udp_socket.recvfrom(1024)
            print(f"[來自{info[0]}:{info[1]}的消息]:\n{data.decode('utf-8')}")

if __name__ == '__main__':
    main()

你會發現,消息不能輪流發送,只能等對方方式後再發,雖然有處理方式,但太麻煩,這時候就可以使用我們之前說的多線程來改寫一下了:

from socket import socket, AF_INET, SOCK_DGRAM
from multiprocessing.dummy import Pool as ThreadPool

def send_msg(udp_socket):
    while True:
        msg = input("輸入需要發送的消息:\n")
        udp_socket.sendto(msg.encode("utf-8"), ("192.168.36.235", 8080))

def recv_msg(udp_socket):
    while True:
        data, info = udp_socket.recvfrom(1024)
        print(f"[來自{info[0]}:{info[1]}的消息]:\n{data.decode('utf-8')}")

def main():
    # 創建一個Socket
    with socket(AF_INET, SOCK_DGRAM) as udp_socket:
        # 綁定埠
        udp_socket.bind(('', 5400))

        # 創建一個線程池
        pool = ThreadPool()

        # 接收消息
        pool.apply_async(recv_msg, args=(udp_socket, ))

        # 發送消息
        pool.apply_async(send_msg, args=(udp_socket, ))

        pool.close()  # 不再添加任務
        pool.join()  # 等待線程池執行完畢
    print("over")

if __name__ == '__main__':
    main()

輸出:(就一個註意點~socket在pool之後關閉2.收放自如.gif


2.3.手寫UDP網路調試工具

調試工具功能比較簡單,我們手寫一個UDP版的:

from socket import socket, AF_INET, SOCK_DGRAM
from multiprocessing.dummy import Pool as ThreadPool

def get_port(msg):
    """獲取用戶輸入的埠號"""
    while True:
        port = input(msg)
        try:
            port = int(port)
        except Exception as ex:
            print(ex)
        else:
            return port  # 沒有錯誤就退出死迴圈

def recv_msg(udp_socket):
    """接收消息"""
    while True:
        data, info = udp_socket.recvfrom(1024)
        print(f"[來自{info[0]}:{info[1]}的消息]:\n{data.decode('utf-8')}")

def send_msg(udp_socket):
    """發送消息"""
    ip = input("請輸入對方IP:")
    port = get_port("請輸入對方埠號:")
    while True:
        msg = input("請輸入發送的消息:\n")
        udp_socket.sendto(msg.encode("utf-8"), (ip, port))

def main():
    with socket(AF_INET, SOCK_DGRAM) as udp_socket:
        # 綁定埠
        udp_socket.bind(('', get_port("請輸網路助手的埠號:")))
        # 創建一個線程池
        pool = ThreadPool()
        # 接收消息
        pool.apply_async(recv_msg, args=(udp_socket, ))
        # 發送消息
        pool.apply_async(send_msg, args=(udp_socket, ))

        pool.close()
        pool.join()

if __name__ == '__main__':
    main()

CentOSIPPort(192.168.36.123:5400) 2.UDP網路助手.png

演示:(多PC演示) 2.UDPTool.gif

簡單說下本機IP的綁定:

Net裡面習慣使用localhost,很多人不知道到底是啥,其實你打開host文件就可以看到 ==> 127.0.0.1被重定向為localhost,在Linux裡面也是這樣的,每個PC對應的都是lo迴環地址: 2.lo.png

本機通信時,對方ip就可以使用127.0.0.1了,當然了綁定本機ip的時候也可以使用127.0.0.1bind(('',))中的空其實填的就是這個)(很多地方也會使用0.0.0.0)

_LOCALHOST    = '127.0.0.1' # 看這
_LOCALHOST_V6 = '::1'

   def socketpair(family=AF_INET, type=SOCK_STREAM, proto=0):
        if family == AF_INET:
            host = _LOCALHOST # 看這
        elif family == AF_INET6:
            host = _LOCALHOST_V6
        ....

        lsock = socket(family, type, proto)
        try:
            lsock.bind((host, 0)) # 看這
            lsock.listen()
            ...

2.4.NetCore版

快速實現一下:

using System.Net;
using System.Text;
using System.Net.Sockets;

namespace netcore
{
    class Program
    {
        static void Main(string[] args)
        {
            // UDP通信
            using (var udp_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
            {
                var ip_addr = IPAddress.Parse("192.168.36.235");

                // 綁定本地埠
                udp_socket.Bind(new IPEndPoint(ip_addr, 5400));
                // UDP發送消息
                int i = udp_socket.SendTo(Encoding.UTF8.GetBytes("小明你好啊~"), new IPEndPoint(ip_addr, 8080));
                Console.WriteLine($"發送計數:{i}");
            }
            Console.WriteLine("over");
        }
    }
}
 

3.TCP

示例代碼:https://github.com/lotapp/BaseCode/tree/master/python/6.net/2.TCP

TCP是一種面向連接的、可靠的協議,TCP傳輸的雙方需要首先建立連接,之後由TCP協議保證數據收發的可靠性,丟失的數據包自動重發,上層應用程式收到的總是可靠的數據流,通訊之後關閉連接(有點像打電話)

用過下載軟體的可能遇到過一種‘Bug’ ==> 很多人為了防止自己本地文件納入共用大軍,一般都是直接把網路上傳給禁了,然後發現文件經常出問題?

其實這個就是TCP的一個應用,文件一般都很大,所以進行分割後批量下載,那少量的網路上傳其實是為了校驗一下文件 ==> 正確做法是限制上傳速度而不是禁止(學生時代那會還經常蛋疼這個問題,現在想想還挺好玩的O(∩_∩)O

大多數連接都是可靠的TCP連接。創建TCP連接時,主動發起連接的叫客戶端,被動響應連接的叫伺服器

上面那個例子里,我們的下載工具就是客戶端,每一小段文件接收完畢後都會向伺服器發送一個完成的指令來保證文件的完整性

3.1.TCP客戶端

來看一個簡單的入門案例:

from socket import socket

def main():
    # 預設就是創建TCP Socket
    with socket() as tcp_socket:
        # 連接伺服器(沒有返回值)
        tcp_socket.connect(("192.168.36.235", 8080))
        # 發送消息(返回發送的位元組數)
        tcp_socket.send("小張生日快樂~".encode("utf-8"))
        # 接收消息
        msg = tcp_socket.recv(1024)
        print(f"伺服器:{msg.decode('utf-8')}")

if __name__ == '__main__':
    main()

輸出:(socket()預設就是創建TCP Socket3.tcp_client.gif

概括來說:

  1. TCP,有點像打電話,先撥號連通了(connect)才能通信(sendrecv),之後的通信不用再撥號連通了
  2. UDP,有點像寄信封,每次寄過去都不確定能不能收到,每次通信都得寫地址(ip+port)

代碼四步走:(TCP客戶端其實創建Socket之後connect一下伺服器就OK了)

  1. 創建:tcp_sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  2. 連接:tcp_sock.connect((IP, Port))
  3. 發送:tcp_sock.send(Bytes內容) 接收:tcp_sock.recv(count)
  4. 關閉:tcp_sock.close()

模擬HTTP

from socket import socket

def get_buffer(tcp_socket):
    buffers = b''
    while True:
        b = tcp_socket.recv(1024)
        if b:
            buffers += b
        else:
            break
    # 返回bytes
    return buffers

def main():
    with socket() as tcp_socket:
        # 連接伺服器
        tcp_socket.connect(("dotnetcrazy.cnblogs.com", 80))
        # 發送消息(模擬HTTP)
        tcp_socket.send(
            b'GET / HTTP/1.1\r\nHost: dotnetcrazy.cnblogs.com\r\nConnection: close\r\n\r\n'
        )
        # 以"\r\n\r\n"分割一次
        header, data = get_buffer(tcp_socket).split(b"\r\n\r\n", 1)
        print(header.decode("utf-8"))
        with open("test.html", "wb") as f:
            f.write(data)
    print("over")

if __name__ == '__main__':
    main()

輸出:(test.html就是頁面源碼)

HTTP/1.1 200 OK
Date: Thu, 01 Nov 2018 03:10:48 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 20059
Connection: close
Vary: Accept-Encoding
Cache-Control: private, max-age=10
Expires: Thu, 01 Nov 2018 03:10:58 GMT
Last-Modified: Thu, 01 Nov 2018 03:10:48 GMT
X-UA-Compatible: IE=10
X-Frame-Options: SAMEORIGIN
over

註意\r\nConnection:closesplit("",分割次數)


3.2.TCP服務端

服務端代碼相比於UDP,多了一個監聽和等待客戶端,其他基本上一樣:

客戶端Code:(如果你想固定埠也可以綁定一下Port)

from socket import socket

def main():
    # 預設就是創建TCP Socket
    with socket() as tcp_socket:
        # 連接伺服器(沒有返回值)
        tcp_socket.connect(("192.168.36.235", 8080))

        print("Connected TCP Server...")  # 連接提示

        # 發送消息(返回發送的位元組數)
        tcp_socket.send("小張生日快樂~\n".encode("utf-8"))
        # 接收消息
        msg = tcp_socket.recv(1024)
        print(f"伺服器:{msg.decode('utf-8')}")

if __name__ == '__main__':
    main()

服務端Code:

from socket import socket

def main():
    with socket() as tcp_socket:
        # 綁定埠(便於客戶端找到)
        tcp_socket.bind(('', 8080))
        # 變成被動接收消息(監聽)
        tcp_socket.listen()  # 不指定連接最大數則會設置預設值

        print("TCP Server is Running...")  # 運行後提示

        # 等待客戶端發信息
        client_socket, client_addr = tcp_socket.accept()

        with client_socket:
            # 客戶端連接提示
            print(f"[來自{client_addr[0]}:{client_addr[1]}的消息]\n")

            # 接收客戶端消息
            data = client_socket.recv(1024)
            print(data.decode("utf-8"))

            # 回覆客戶端
            client_socket.send("知道了".encode("utf-8"))

if __name__ == '__main__':
    main()

輸出:(先運行服務端,再運行客戶端。客戶端發了一個生日快樂的祝福,服務端回覆了一句) 3.tcp_server.gif

3.2.TCP服務端調試助手

如果像上面那般,並不能多客戶端通信 3.bug.png

這時候可以稍微改造一下:

客戶端:

from time import sleep
from socket import socket
from multiprocessing.dummy import Pool

def send_msg(tcp_socket):
    with tcp_socket:
        while True:
            try:
                tcp_socket.send("小明同志\n".encode("utf-8"))
                sleep(2)  # send是非阻塞的
                print("向伺服器問候了一下")
            except Exception as ex:
                print("服務端連接已斷開:", ex)
                break

def recv_msg(tcp_socket):
    with tcp_socket:
        while True:
            # 這邊可以不捕獲異常:
            #    服務端關閉時,send_msg會關閉,然後這邊也就關閉了
            try:
                data = tcp_socket.recv(1024)
                if data:
                    print("服務端回覆:", data.decode("utf-8"))
            except Exception as ex:
                print("tcp_socket已斷開:", ex)
                break

def main():
    with socket() as tcp_socket:
        # 連接TCP Server
        tcp_socket.connect(("192.168.36.235", 8080))
        print("Connected TCP Server...")  # 連接提示

        pool = Pool()
        pool.apply_async(send_msg, args=(tcp_socket,))
        pool.apply_async(recv_msg, args=(tcp_socket,))
        pool.close()
        pool.join()

if __name__ == '__main__':
    main()

服務端

伺服器需要同時響應多個客戶端的請求,那麼每個連接都需要一個新的進程或者線程來處理

from socket import

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • public static void main(String[] args) { int [] a= {1,3,5,7,9,2,4,6}; Sorts(a,0,a.length-1); for(int i=0;i<a.length-1;i++) { System.out.print(a[i]+" " ...
  • 1、reactor(反應器)模式 使用單線程模擬多線程,提高資源利用率和程式的效率,增加系統吞吐量。下麵例子比較形象的說明瞭什麼是反應器模式: 一個老闆經營一個飯店, 傳統模式 來一個客人安排一個服務員招呼,客人很滿意;(相當於一個連接一個線程) 後來客人越來越多,需要的服務員越來越多,資源條件不足 ...
  • switch-case與if-else有相似的作用,都是表達分支的方式。 語法形式: switch語句的特點: type和case後面的值都必須是常量或常量表達式; break和default儘量不要省略(特殊用途下break可省略); 可以將switch語句理解成高速公路,case 常量 為入口, ...
  • 前言 最近學到了二叉樹,就學著將二叉樹構造,並嘗試三種遍歷操作。本次主要使用遞歸,回頭會整理非遞歸的方法。 定義二叉樹 其中要註意Node是結構體指針,這樣定義以後使用會方便很多。 構造二叉樹 1 Node CreatTree() 2 { 3 Node p; 4 TelemType a; 5 cin ...
  • SpringBoot是一種用來簡化新Spring應用初始搭建及開發過程的框架,它使用特定方式來進行配置,使得開發人員不再需要定義樣板化的配置。MyBatis是一個支持普通SQL查詢、存儲和高級映射的持久層框架,它消除了幾乎所有的JDBC代碼和參數的手工配置以及對結果集的檢索封裝,可以使用簡單的XML ...
  • 多線程 std::call_once的應用 std::call_once的應用:類成員的延遲初始化,並只初始化一次。和static的作用很像,都要求是線程安全的,c++11之前在多線程的環境下,static好像不是線程安全的,c++11開始,static是線程安全的了。 註意:即使某一個特定的線程里 ...
  • 高級類特性 (類的成員之一:內部類) 內的成員之一:內部類(屬性、方法、構造器、代碼塊) 可以有四種許可權訪問修飾符 註意:外部類 只有兩種 public 和 default 定義 : 可以將一個類的定義放在另一個類定義的內部,這就是內部類 thinking in Java 用法:如果一個類 僅跟本類 ...
  • 題意 "題目鏈接" Sol 一步一步的來考慮 $25 \%$:直接$O(nm)$的暴力 鏈的情況:維護兩個差分數組,分別表示從左向右和從右向左的貢獻, $S_i = 1$:統計每個點的子樹內有多少起點即可 $T_i = 1$:同樣還是差分的思想,由於每個點 能對其產生的點的深度是相同的(假設為$x$ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...