91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何用Python分析TCP服務器與客戶端

發布時間:2021-12-04 10:34:24 來源:億速云 閱讀:156 作者:柒染 欄目:網絡安全

本篇文章給大家分享的是有關如何用Python分析TCP服務器與客戶端,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

0x00 前言

「網絡」一直以來都是黑客最熱衷的競技場。數據在網絡中肆意傳播:主機掃描、代碼注入、網絡嗅探、數據篡改重放、拒絕服務攻擊......黑客的功底越深厚,能做的就越多。

Python 作為一種解釋型腳本語言,自 1991 年問世以來,其簡潔、明確、可讀性強的語法深受黑客青睞,特別在網絡工具的編寫上,避免了繁瑣的底層語法,沒有對運行速度的高效要求,使得 Python 成為安全工作者的必備殺手锏。

小編先介紹因特網的核心協議——TCP 協議,再以 Python 的 socket 模塊為例介紹網絡套接字,最后給出 TCP 服務器與客戶端的 Python 腳本,并演示兩者之間的通信過程。

0x01 TCP 協議

TCP(Transmission Control Protocol,傳輸控制協議)是一種面向連接、可靠的、基于字節流的傳輸層通信協議。

TCP 協議的運行分為連接創建(Connection Establishment)、數據傳送(Data Transfer)和連接終止(Connection Termination)三個階段,其中「連接創建」階段是耳熟能詳的 TCP 協議三次握手(TCP Three-way Handshake),也是理解本文 TCP 服務器與客戶端通信過程的階段。

連接創建(Connection Establishment)

所謂的「三次握手」,即 TCP 服務器與客戶端成功建立通信連接必經的三個步驟,共需通過三個報文完成。

Handshake Step 1

客戶端向服務器發送 SYN 報文(SYN = 1)請求連接。此時報文的初始序列號為 seq = x,確認號為 ack = 0。

Handshake Step 2

服務器接收到客戶端的 SYN 報文后,發送 ACK + SYN 報文(ACK = 1,SYN = 1)確認客戶端的連接請求,并也向其發起連接請求。此時報文的序列號為 seq = y,確認號為 ack = x + 1。

Handshake Step 3

客戶端接收到服務器的 SYN 報文后,發送 ACK 報文(ACK = 1)確認服務器的連接請求。此時報文的序列號為 seq = x + 1,確認號為 ack = y + 1。

對于上述過程的理解,需要注意以下幾點:

  • 報文的功能在 TCP 協議頭的標記符(Flags)區段中定義,該區段位于第 104~111 比特位,共占 8 比特,每個比特位對應一種功能,置 1 代表開啟,置 0 代表關閉。例如,SYN 報文的標記符為 00000010,ACK + SYN 報文的標記符為 00010010

  • 報文的序列號在 TCP 協議頭的序列號(Sequence Number)區段中定義,該區段位于第 32~63 比特位,共占 32 比特。在「三次握手」過程中,初始序列號 seq 由數據發送方隨機生成。

  • 報文的確認號在 TCP 協議頭的確認號(Acknowledgement Number)區段中定義,該區段位于第 64~95 比特位,共占 32 比特。在「三次握手」過程中,確認號 ack 為前序接收報文的序列號加 1。

為了更方便地理解,下面給出一張 TCP 協議三次握手的示意圖:


如何用Python分析TCP服務器與客戶端

0x02 Network Socket

Network Socket(網絡套接字)是計算機網絡中進程間通信的數據流端點,廣義上也代表操作系統提供的一種進程間通信機制。

進程間通信(Inter-Process Communication,IPC)的根本前提是能夠唯一標示每個進程。在本地主機的進程間通信中,可以用 PID(進程 ID)唯一標示每個進程,但 PID 只在本地唯一,在網絡中不同主機的 PID 則可能發生沖突,因此采用「IP 地址 + 傳輸層協議 + 端口號」的方式唯一標示網絡中的一個進程。

小貼士:網絡層的 IP 地址可以唯一標示主機,傳輸層的 TCP/UDP 協議和端口號可以唯一標示該主機的一個進程。注意,同一主機中 TCP 協議與 UDP 協議的可以使用相同的端口號。

所有支持網絡通信的編程語言都各自提供了一套 socket API,下面以 Python 3 為例,講解服務器與客戶端建立 TCP 通信連接的交互過程:


如何用Python分析TCP服務器與客戶端

腦海中先對上述過程產生一定印象后,更易于理解下面兩節 TCP 服務器與客戶端的 Python 實現。

0x03 TCP 服務器

#!/usr/bin/env python3# -*- coding: utf-8 -*-import socketimport threadingdef tcplink(conn, addr):        print("Accept new connection from %s:%s" % addr)
        conn.send(b"Welcome!\n")
        while True:
                conn.send(b"What's your name?")
                data = conn.recv(1024).decode()
                if data == "exit":
                        conn.send(b"Good bye!\n")
                        break                conn.send(b"Hello %s!\n" % data.encode())
        conn.close()
        print("Connection from %s:%s is closed" % addr)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("127.0.0.1", 6000))
s.listen(5)
print("Waiting for connection...")while True:
        conn, addr = s.accept()
        t = threading.Thread(target = tcplink, args = (conn, addr))
        t.start()
  • Line 6:定義一個 tcplink() 函數,第一個 conn 參數為服務器與客戶端交互數據的套接字對象,第二個 addr 參數為客戶端的 IP 地址與端口號,用二元組 (host, port) 表示。

  • Line 8:連接成功后,向客戶端發送問候信息 "Welcome!\n"

  • Line 9:進入與客戶端交互數據的循環階段。

  • Line 10:向客戶端發送詢問信息 "What's your name?"

  • Line 11:接收客戶端發來的非空字符串。

  • Line 12:如果非空字符串為 "exit",則向客戶端發送結束信息 "Good bye!\n",并結束與客戶端交互數據的循環階段。

  • Line 15:如果非空字符串不為 "exit",則向客戶端發送問候信息 "Hello %s!\n",其中 %s 是客戶端發來的非空字符串。

  • Line 16:關閉套接字,不再向客戶端發送數據。

  • Line 19:創建 socket 對象,第一個參數為 socket.AF_INET,代表采用 IPv4 協議用于網絡通信,第二個參數為 socket.SOCK_STREAM,代表采用 TCP 協議用于面向連接的網絡通信。

  • Line 20:向 socket 對象綁定服務器主機地址 ("127.0.0.1", 6000),即本地主機的 TCP 6000 端口。

  • Line 21:開啟 socket 對象的監聽功能,等待客戶端的連接請求。

  • Line 24:進入監聽客戶端連接請求的循環階段。

  • Line 25:接收客戶端的連接請求,并獲得與客戶端交互數據的套接字對象 conn 與客戶端的 IP 地址與端口號 addr,其中 addr 為二元組 (host, port)。

  • Line 26:利用多線程技術,為每個請求連接的 TCP 客戶端創建一個新線程,實現了一臺服務器同時與多臺客戶端進行通信的功能。

  • Line 27:開啟新線程的活動。

0x04 TCP 客戶端

#!/usr/bin/env python3# -*- coding: utf-8 -*-import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 6000))
print(s.recv(1024).decode())

data = "client"while True:
        if data:
                print(s.recv(1024).decode())
        data = input("Please input your name: ")
        if not data:
                continue        s.send(data.encode())
        print(s.recv(1024).decode())
        if data == "exit":
                breaks.close()
  • Line 5:創建 socket 對象,第一個參數為 socket.AF_INET,代表采用 IPv4 協議用于網絡通信,第二個參數為 socket.SOCK_STREAM,代表采用 TCP 協議用于面向連接的網絡通信。

  • Line 6:向 ("127.0.0.1", 6000) 主機發起連接請求,即本地主機的 TCP 6000 端口。

  • Line 7:連接成功后,接收服務器發送過來的問候信息 "Welcome!\n"

  • Line 9:創建一個非空字符串變量 data,并賦初值為 "client"(只要是非空字符串即可),用于判斷是否接收來自服務器發來的詢問信息 "What's your name?"

  • Line 10:進入與服務器交互數據的循環階段。

  • Line 12:當用戶的輸入非空且不等于 "exit"(記為非法字符串)時,則接收服務器發來的詢問信息。

  • Line 13:要求用戶輸入名字,一條合法字符串即可。

  • Line 14:當用戶輸入非空,則重新開始循環,要求用戶重新輸入合法字符串。

  • Line 16:當用戶輸入合法字符串時,則將字符串轉換為 bytes 對象后發送至服務器。

  • Line 17:接收服務器的響應數據,并將 bytes 對象轉換為字符串后打印輸出。

  • Line 18:當用戶輸入字符串 "exit" 時,則結束與服務器交互數據的循環階段,即將關閉套接字。

  • Line 21:關閉套接字,不再向服務器發送數據。

0x05 TCP 進程間通信

將 TCP 服務器與客戶端的腳本分別命名為 tcp_server.py 與 tcp_client.py,然后存至桌面,筆者將在 Windows 10 系統下用 PowerShell 進行演示。

小貼士:讀者進行復現時,要確保本機已安裝 Python 3,注意筆者已將默認的啟動路徑名 python 改為了 python3

單服務器 VS 單客戶端


如何用Python分析TCP服務器與客戶端

  1. 在其中一個 PowerShell 中運行命令 python3 ./tcp_server.py,服務器顯示 Waiting for connection...,并監聽本地主機的 TCP 6000 端口,進入等待連接狀態;

  2. 在另一個 PowerShell 中運行命令 python3 ./tcp_client.py,服務器顯示 Accept new connection from 127.0.0.1:42101,完成與本地主機的 TCP 42101 端口建立通信連接,并向客戶端發送問候信息與詢問信息,客戶端接收到信息后打印輸出;

  3. 若客戶端向服務器發送字符串 Alice 與 Bob,則收到服務器的問候響應信息;

  4. 若客戶端向服務器發送空字符串,則要求重新輸入字符串;

  5. 若客戶端向服務器發送字符串 exit,則收到服務器的結束響應信息;

  6. 客戶端與服務器之間的通信連接已關閉,服務器顯示 Connection from 127.0.0.1:42101 is closed,并繼續監聽客戶端的連接請求。

單服務器 VS 多客戶端

如何用Python分析TCP服務器與客戶端

  1. 在其中一個 PowerShell 中運行命令 python3 ./tcp_server.py,服務器顯示 Waiting for connection...,并監聽本地主機的 TCP 6000 端口,進入等待連接狀態;

  2. 在另三個 PowerShell 中分別運行命令 python3 ./tcp_client.py,服務器同時與本地主機的 TCP 42719、42721、42722 端口建立通信連接,并分別向客戶端發送問候信息與詢問信息,客戶端接收到信息后打印輸出;

  3. 三臺客戶端分別向服務器發送字符串 Client1Client2Client3,并收到服務器的問候響應信息;

  4. 所有客戶端分別向服務器發送字符串 exit,并收到服務器的結束響應信息;

  5. 所有客戶端與服務器之間的通信連接已關閉,服務器繼續監聽客戶端的連接請求。

0x06 Python API Reference

socket 模塊

此小節介紹上述代碼中用到的 socket 模塊內置函數,也是 socket 編程的核心函數。

socket() 函數

socket() 函數用于創建網絡通信中的套接字對象。函數原型如下:

socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
  • family 參數代表地址族(Address Family),默認值為 AF_INET,用于 IPv4 網絡通信,常用的還有 AF_INET6,用于 IPv6 網絡通信。family 參數的可選值取決于本機操作系統。

  • type 參數代表套接字的類型,默認值為 SOCK_STREAM,用于 TCP 協議(面向連接)的網絡通信,常用的還有 SOCK_DGRAM,用于 UDP 協議(無連接)的網絡通信。

  • proto 參數代表套接字的協議,默認值為 0,一般忽略該參數,除非 family 參數為 AF_CAN,則 proto 參數需設置為 CAN_RAW 或 CAN_BCM。

  • fileno 參數代表套接字的文件描述符,默認值為 None,若設置了該參數,則其他三個參數將會被忽略。

socket 對象

此小節介紹上述代碼中用到的 socket 對象內置函數,也是 socket 編程的常見函數。注意,以下函數原型中的「socket」是指 socket 對象,而不是 socket 模塊。

bind() 函數

bind() 函數用于向套接字對象綁定 IP 地址與端口號。注意,套接字對象必須未被綁定,并且端口號未被占用,否則會報錯。函數原型如下:

socket.bind(address)
  • address 參數代表套接字要綁定的地址,其格式取決于套接字的 family 參數。若 family 參數為 AF_INET,則 address 參數表示為二元組 (host, port),其中 host 是用字符串表示的主機地址,port 是用整型表示的端口號。

listen() 函數

listen() 函數用于 TCP 服務器開啟套接字的監聽功能。函數原型如下:

socket.listen([backlog])
  • backlog 可選參數代表套接字在拒絕新連接之前,操作系統可以掛起的最大連接數。backlog 參數一般設置為 5,若未設置,系統會為其自動設置一個合理的值。

connect() 函數

connect() 函數用于 TCP 客戶端向 TCP 服務器發起連接請求。函數原型如下:

socket.connect(address)
  • address 參數代表套接字要連接的地址,其格式取決于套接字的 family 參數。若 family 參數為 AF_INET,則 address 參數表示為二元組 (host, port),其中 host 是用字符串表示的主機地址,port 是用整型表示的端口號。

accept() 函數

accept() 函數用于 TCP 服務器接受 TCP 客戶端的連接請求。函數原型如下:

socket.accept()

accept() 函數的返回值是一個二元組 (conn, address),其中 conn 是服務器用來與客戶端交互數據的套接字對象,address 是客戶端的 IP 地址與端口號,用二元組 (host, port) 表示。

send() 函數

send() 函數用于向遠程套接字對象發送數據。注意,本機的套接字必須與遠程的套接字成功連接后才能使用該函數,否則會報錯。可見,send() 函數只能用于 TCP 進程間通信,而對于 UDP 進程間通信應該用 sendto() 函數。函數原型如下:

socket.send(bytes[, flags])
  • bytes 參數代表即將發送的 bytes 對象數據。例如,對于字符串 "hello world!" 而言,需要用 encode() 函數轉換為 bytes 對象 b"hello world!" 才能進行網絡傳輸。

  • flags 可選參數用于設置 send() 函數的特殊功能,默認值為 0,也可由一個或多個預定義值組成,用位或操作符 |隔開。詳情可參考 Unix 函數手冊中的 send(2),flags 參數的常見取值有 MSG_OOB、MSG_PEEK、MSG_WAITALL 等。

send() 函數的返回值是發送數據的字節數。

recv() 函數

recv() 函數用于從遠程套接字對象接收數據。注意,與 send() 函數不同,recv() 函數既可用于 TCP 進程間通信,也能用于 UDP 進程間通信。函數原型如下:

socket.recv(bufsize[, flags])
  • bufsize 參數代表套接字可接收數據的最大字節數。注意,為了使硬件設備與網絡傳輸更好地匹配,bufsize 參數的值最好設置為 2 的冪次方,例如 4096。

  • flags 可選參數用于設置 recv() 函數的特殊功能,默認值為 0,也可由一個或多個預定義值組成,用位或操作符 |隔開。詳情可參考 Unix 函數手冊中的 recv(2),flags 參數的常見取值有 MSG_OOB、MSG_PEEK、MSG_WAITALL 等。

recv() 函數的返回值是接收到的 bytes 對象數據。例如,接收到 bytes 對象 b"hello world!",最好用 decode() 函數轉換為字符串 "hello world!" 再打印輸出。

close() 函數

close() 函數用于關閉本地套接字對象,釋放與該套接字連接的所有資源。

socket.close()

threading 模塊

此小節介紹上述代碼中用到的 threading 模塊內置類,也是 Python 多線程編程的核心。

Thread() 類

Thread() 類可以創建線程對象,用于調用 start() 函數啟動新線程。類原型如下:

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
  • group 參數作為以后實現 ThreadGroup() 類的保留參數,目前默認值為 None。

  • target 參數代表線程被 run() 函數激活后調用的函數,默認值為 None,即沒有任何函數會被調用。

  • name 參數代表線程名,默認值為 None,則系統會自動為其命名,格式為「Thread-N」,N 是從 1 開始的十進制數。

  • args 參數代表 target 參數指向函數的普通參數,用元組(tuple)表示,默認值為空元組 ()

  • kwargs 參數代表 target 參數指向函數的關鍵字參數,用字典(dict)表示,默認值為空字典 {}

  • daemon 參數用于標示進程是否為守護進程。若設置為 True,則標示為守護進程;若設置為 False,則標示為非守護進程;若設置為 None,則繼承當前父線程的 daemon 參數值。

threading 對象

此小節介紹上述代碼中用到的 threading 對象內置函數,也是多線程編程的必用函數。注意,以下函數原型中的「threading」是指 threading 對象,而不是 threading 模塊。

start() 函數

start() 函數用于開啟線程活動。函數原型如下:

threading.start()

注意,每個線程對象只能調用一次 start() 函數,否則會導致 RuntimeError 錯誤。

以上就是如何用Python分析TCP服務器與客戶端,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

牡丹江市| 青冈县| 卢湾区| 新建县| 米林县| 防城港市| 奉化市| 华宁县| 应城市| 吉安县| 垫江县| 瑞安市| 盐池县| 招远市| 沁源县| 德庆县| 天峻县| 屯门区| 栾城县| 达日县| 华坪县| 疏勒县| 石棉县| 瓮安县| 北安市| 嵊泗县| 台南市| 罗江县| 平谷区| 鞍山市| 拉萨市| 偃师市| 曲阳县| 梅州市| 汾阳市| 宜宾市| 安溪县| 海口市| 陵川县| 金湖县| 茶陵县|