python網路程式設計理解

2022-04-30 02:21:10 字數 4205 閱讀 1969

和客戶端程式設計相比,伺服器程式設計就要複雜一些。

伺服器程序首先要繫結乙個埠並監聽來自其他客戶端的連線。如果某個客戶端連線過來了,伺服器就與該客戶端建立socket連線,隨後的通訊就靠這個socket連線了。

所以,伺服器會開啟固定埠(比如80)監聽,每來乙個客戶端連線,就建立該socket連線。由於伺服器會有大量來自客戶端的連線,所以,伺服器要能夠區分乙個socket連線是和哪個客戶端繫結的。乙個socket依賴4項:伺服器位址、伺服器端口、客戶端位址、客戶端埠來唯一確定乙個socket。

但是伺服器還需要同時響應多個客戶端的請求,所以,每個連線都需要乙個新的程序或者新的執行緒來處理,否則,伺服器一次就只能服務乙個客戶端了。

我們來編寫乙個簡單的伺服器程式,它接收客戶端連線,把客戶端發過來的字串加上hello再發回去。

首先,建立乙個基於ipv4和tcp協議的socket:

s = socket.socket(socket.af_inet, socket.sock_stream)

然後,我們要繫結監聽的位址和埠。伺服器可能有多塊網絡卡,可以繫結到某一塊網絡卡的ip位址上,也可以用0.0.0.0繫結到所有的網路位址,還可以用127.0.0.1繫結到本機位址。127.0.0.1是乙個特殊的ip位址,表示本機位址,如果繫結到這個位址,客戶端必須同時在本機執行才能連線,也就是說,外部的計算機無法連線進來。

埠號需要預先指定。因為我們寫的這個服務不是標準服務,所以用9999這個埠號。請注意,小於1024的埠號必須要有管理員許可權才能繫結:

監聽埠:

s.bind(('127.0.0.1', 9999))

緊接著,呼叫listen()方法開始監聽埠,傳入的引數指定等待連線的最大數量:

s.listen(5)

print('waiting for connection...')

接下來,伺服器程式通過乙個永久迴圈來接受來自客戶端的連線,accept()會等待並返回乙個客戶端的連線:

while true:

接受乙個新連線:

sock, addr = s.accept()

建立新執行緒來處理tcp連線:

t = threading.thread(target=tcplink, args=(sock, addr))

t.start()

每個連線都必須建立新執行緒(或程序)來處理,否則,單執行緒在處理連線的過程中,無法接受其他客戶端的連線:

def tcplink(sock, addr):

print('accept new connection from %s:%s...' % addr)

sock.send(b'welcome!')

while true:

data = sock.recv(1024)

time.sleep(1)

if not data or data.decode('utf-8') == 'exit':

break

sock.send(('hello, %s!' % data.decode('utf-8')).encode('utf-8'))

sock.close()

print('connection from %s:%s closed.' % addr)

連線建立後,伺服器首先發一條歡迎訊息,然後等待客戶端資料,並加上hello再傳送給客戶端。如果客戶端傳送了exit字串,就直接關閉連線。

要測試這個伺服器程式,我們還需要編寫乙個客戶端程式:

s = socket.socket(socket.af_inet, socket.sock_stream)

建立連線:

s.connect(('127.0.0.1', 9999))

接收歡迎訊息:

print(s.recv(1024).decode('utf-8'))

傳送資料:

s.send(data)

print(s.recv(1024).decode('utf-8'))

s.send(b'exit')

s.close()

伺服器程式設計:

1.開啟socket;2.繫結到特定的位址以及埠上;3.監聽連線;4.建立連線;5.接收/傳送資料 

繫結socekt:函式bind可以用來將socket繫結到特定的位址和埠上,繫結完成後,可以開啟監聽模式

監聽連線listen:將socket置於監聽模式,該函式帶有乙個引數backlog,用來控制連線的個數,如果設為10,那麼有10個連線正在等待處理,此時,第11個請求過來時,將會被拒絕。

接收連線:當有客戶端向伺服器傳送連線請求時,伺服器會接收連線

客戶端程式的編寫如下:

accept函式的理解:

accept返回的socket(記為socket1)是乙個不同於socket建立的socket(記為socket2),socket2是用來監聽和建立連線的,不能進行資料的傳送與接收(所以這個socket不需要客戶端的資訊,它就是用於監聽連線的),socket1是專門用於傳送接收資料的,他記錄的資訊是所連線的客戶端socket的資訊,記錄的是客戶端的協議位址,addr就是客戶端的ip位址,埠號元組,這個埠號是由客戶端來確定的,之所以會這樣理解是因為,客戶端自身肯定知道自身的ip,埠,要進行通訊,肯定只需要對方的ip,埠好,同樣伺服器端要傳送接收資料,也要知道客戶端的協議位址埠號才行,如果記錄的是自身的資訊,就沒法與客戶端通訊了。

tcp是建立可靠連線,並且通訊雙方都可以以流的形式傳送資料。相對tcp,udp則是面向無連線的協議。

使用udp協議時,不需要建立連線,只需要知道對方的ip位址和埠號,就可以直接發資料報。但是,能不能到達就不知道了。

雖然用udp傳輸資料不可靠,但它的優點是和tcp比,速度快,對於不要求可靠到達的資料,就可以使用udp協議。

我們來看看如何通過udp協議傳輸資料。和tcp類似,使用udp的通訊雙方也分為客戶端和伺服器。伺服器首先需要繫結埠:

s = socket.socket(socket.af_inet, socket.sock_dgram)

繫結埠:

s.bind(('127.0.0.1', 9999))

建立socket時,sock_dgram指定了這個socket的型別是udp。繫結埠和tcp一樣,但是不需要呼叫listen()方法,而是直接接收來自任何客戶端的資料:

print('bind udp on 9999...')

while true:

接收資料:

data, addr = s.recvfrom(1024)

print('received from %s:%s.' % addr)

s.sendto(b'hello, %s!' % data, addr)

recvfrom()方法返回資料和客戶端的位址與埠,這樣,伺服器收到資料後,直接呼叫sendto()就可以把資料用udp發給客戶端。

注意這裡省掉了多執行緒,因為這個例子很簡單。

客戶端使用udp時,首先仍然建立基於udp的socket,然後,不需要呼叫connect(),直接通過sendto()給伺服器發資料:

s = socket.socket(socket.af_inet, socket.sock_dgram)

for data in [b'michael', b'tracy', b'sarah']:

傳送資料:

s.sendto(data, ('127.0.0.1', 9999))

接收資料:

print(s.recv(1024).decode('utf-8'))

s.close()

從伺服器接收資料仍然呼叫recv()方法。

客戶端程式設計**

伺服器端程式設計**

socket引數理解

accept函式的理解

listten函式的理解

socket的理解

python網路程式設計

深入理解 Python網路程式設計

乙個簡單的socket案例 socket粘包的概念 socketserver 高階 開發的過程遇到的坑以及心得 待更新一些網路知識 啥是ddos攻擊 洪水攻擊 就是一些機器通過偽造ip位址頭,不斷的去訪問 攻擊 乙個 導致 的崩潰的現象,乙個 能接受的併發量是有限的,通過洪水攻擊,十幾台機器大量偽造...

網路程式設計序列1 理解網路程式設計

常用的tcp ip協議的三種套接字型別 流套接字 tcp協議 資料報套接字 udp協議 原始套接字 ip icmo協議 區別在於 原始套接字可以讀寫核心沒有處理的ip資料報,而流套接字只能讀取tcp協議的資料,資料報套接字只能讀取udp協議的資料。tcp transmission control p...

網路程式設計 TCP理解

談到tcp就必須知道面向連線和可靠傳輸協議,什麼是面向連線?就要說到3次握手下面這張圖就是tcp的3次握手圖 當客戶端想要連線服務端時,會由客戶端的傳輸控制層傳送乙個 sync 包,然後服務端收到後會返回乙個 sync ack 表示知道 包,最後客戶端會在傳送乙個 ack 確定包,只有雙方都確定自己...