前言
Python語(yǔ)言提供了Socket套接字來(lái)實(shí)現(xiàn)網(wǎng)絡(luò)通信。
Python的應(yīng)用程序通常通過(guò)Socket"套接字"向網(wǎng)絡(luò)發(fā)出請(qǐng)求或者應(yīng)答網(wǎng)絡(luò)請(qǐng)求,使主機(jī)間或者一臺(tái)計(jì)算機(jī)上的進(jìn)程間可以通訊。
服務(wù)器和客戶端的源代碼
服務(wù)器端
#coding=utf-8
#創(chuàng)建TCP服務(wù)器
import socket
import time
from time import ctime
HOST = '127.0.0.1'
PORT = 8080
BUFSIZE=1024
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(5)
addr=(HOST,PORT)
while True:
print('waiting for connection...')
sock,addr =sock.accept()
print('...connected from:',addr)
while True:
data =sock.recv(BUFSIZE).decode()
print('date=',data)
if not data:
break
sock.send(('[%s] %s' %(ctime(),data)).encode())
sock.close()
客戶端
#coding=utf-8
#創(chuàng)建TCP客戶端
import socket
HOST = '127.0.0.1'
PORT = 8080
BUFSIZE = 1024
ADDR=(HOST,PORT)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
while True:
data = input('> ')
if not data:
break
sock.send(data.encode())
data = sock.recv(BUFSIZE).decode()
if not data:
break
print(data)
sock.close()
執(zhí)行結(jié)果顯示:
首先執(zhí)行服務(wù)器端,結(jié)果如圖1:
緊接著執(zhí)行客戶端,如圖2
需要注意的是:服務(wù)器端和客戶端需要在兩個(gè)IDLE Shell中打開,否則客戶機(jī)一啟動(dòng),服務(wù)器程序就會(huì)中止執(zhí)行,而客戶端又連不上服務(wù)器,從而報(bào)錯(cuò),如圖3
我們?cè)趫D2中輸入一些需要傳輸?shù)男畔?,然后回車,在服?wù)端可以看到收到了相關(guān)信息,如圖4(客戶端發(fā)送信息),圖5(服務(wù)器端接收信息)
源代碼解析
我們從服務(wù)器端開始看起,先上一部分代碼:
import socket
import time
from time import ctime
這三句是導(dǎo)入了三個(gè)模塊,分別是socket 模塊、time模塊和ctime模塊。
1)socket 模塊當(dāng)中提供了與socket 套接字相關(guān)的各項(xiàng)功能,后面用到了很多,這里先介紹一個(gè),其他一會(huì)再介紹:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
功能:創(chuàng)建套接字,并把創(chuàng)建好的套接字賦給一個(gè)變量sock,下面程序中與套接字相關(guān)的操作都由sock來(lái)完成。
格式:socket.socket([family[, type[, proto]]])
參數(shù):
family: 套接字家族,可以使 AF_UNIX 或者 AF_INET。AF_INET,是指面向網(wǎng)絡(luò)的,因特網(wǎng);AF_UNIX,基于文件的;在本例中,我們使用AF_INET,利用因特網(wǎng)來(lái)進(jìn)行通信。
type: 套接字類型,可以根據(jù)是面向連接的還是非連接分為 SOCK_STREAM 或 SOCK_DGRAM。
SOCK_STREAM:對(duì)應(yīng)著TCP,提供了一個(gè)面向連接、可靠的數(shù)據(jù)傳輸服務(wù),數(shù)據(jù)無(wú)差錯(cuò)、無(wú)重復(fù)的發(fā)送且按發(fā)送順序接收。內(nèi)設(shè)置流量控制,避免數(shù)據(jù)流淹沒慢的接收方。數(shù)據(jù)被看作是字節(jié)流,無(wú)長(zhǎng)度限制。
SOCK_DGRAM:對(duì)應(yīng)著UDP,提供無(wú)連接服務(wù)。數(shù)據(jù)包以獨(dú)立數(shù)據(jù)包的形式被發(fā)送,不提供無(wú)差錯(cuò)保證,數(shù)據(jù)可能丟失或重復(fù),順序發(fā)送,可能亂序接收。
本例中選TCP協(xié)議。
protocol: 一般不填默認(rèn)為 0。
2)time模塊,完成python中與時(shí)間相關(guān)的計(jì)算,例如time.sleep(5)延時(shí)5秒,time time() 返回當(dāng)前時(shí)間的時(shí)間戳等等。
下面的ctime也是其中一個(gè)功能,函數(shù)把一個(gè)時(shí)間戳(按秒計(jì)算的浮點(diǎn)數(shù))轉(zhuǎn)化為time.asctime()的形式,可以便于我們觀察。轉(zhuǎn)換以后的格式如下:
print “time.ctime() : %s” % time.ctime()
結(jié)果:time.ctime() : Tue Feb 17 10:00:18 2013
在我們的例子中,圖4的圈2所表示的就是轉(zhuǎn)換后的時(shí)間。
HOST = '127.0.0.1'
PORT = 8080
BUFSIZE=1024
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(5)
addr=(HOST,PORT)
看完頭部之后,我們來(lái)看第二部分。
前三句定義了三個(gè)變量:HOST、PORT、BUFSIZE,這三個(gè)變量分別是服務(wù)器的IP地址,服務(wù)器的端口,接收的最大數(shù)據(jù)量。
第四句sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 定義了socket 套接字。
第五句sock.bind((HOST, PORT)),將IP地址和端口綁定給定義的套接字sock。
第六句sock.listen(5),開始 TCP 監(jiān)聽。中間的5表示在拒絕連接之前,操作系統(tǒng)可以掛起的最大連接數(shù)量。該值至少為 1,大部分應(yīng)用程序設(shè)為 5 就可以了。
第七句addr=(HOST,PORT),定義了一個(gè)變量addr,并且將地址以元組的形式賦值給addr。
while True:
print('waiting for connection...')
sock,addr =sock.accept()
print('...connected from:',addr)
while True:
data =sock.recv(BUFSIZE).decode()
print('date=',data)
if not data:
break
sock.send(('[%s] %s' %(ctime(),data)).encode())
sock.close()
sock.close()
這是服務(wù)器代碼的最后一部分,也是通信的主體,首先進(jìn)入一個(gè)while True:的永真循環(huán),進(jìn)入之后執(zhí)行print(‘waiting for connection…'),這就是圖1上藍(lán)色字所表示的一部分。
第三行執(zhí)行sock,addr =sock.accept(),sock.accept()是被動(dòng)接受TCP客戶端連接,(阻塞式)等待連接的到來(lái),當(dāng)客戶機(jī)啟動(dòng)提交請(qǐng)求后,服務(wù)器接受請(qǐng)求,并將客戶端的IP地址等信息存入變量addr中。
第四行執(zhí)行print('…connected from:',addr),所以輸入字符串…connected from:以及客戶端傳來(lái)的IP地址和端口。
以上服務(wù)器和客戶端的通信就連接起來(lái)了。
下面開始傳送數(shù)據(jù),又進(jìn)入一個(gè)永真循環(huán),代碼:
while True:
data =sock.recv(BUFSIZE).decode()
print('date=',data)
if not data:
break
sock.send(('[%s] %s' %(ctime(),data)).encode())
sock.close()
第二行:data =sock.recv(BUFSIZE).decode()。
sock.recv()表示接收 TCP 數(shù)據(jù),數(shù)據(jù)以字符串形式返回,BUFSIZE指定要接收的最大數(shù)據(jù)量。
decode() 將其他編碼的字符串解碼成unicode格式。
這里要說(shuō)明一下,上圖:
字符串在python內(nèi)部是用unicode編碼來(lái)表示,而在硬盤是utf-8格式。所以在存儲(chǔ)和使用時(shí)要進(jìn)行格式轉(zhuǎn)換,轉(zhuǎn)換的方式:
decode 將其他編碼的字符串(例如utf-8)解碼成unicode格式。
encode 將unicode編碼成另一種編碼格式(例如utf-8)。
當(dāng)然decode和encode 不止可以轉(zhuǎn)換utf-8類型,轉(zhuǎn)換的類型可以通過(guò) encoding 來(lái)指定,不過(guò)我們常用的就是這個(gè)。
總結(jié)一下,data =sock.recv(BUFSIZE).decode()執(zhí)行結(jié)束就表示把客戶端的數(shù)據(jù)接收過(guò)來(lái)存放到了data這個(gè)變量中。
下面進(jìn)行第三行print(‘date=',data),打印數(shù)據(jù),結(jié)果就是圖5中的圈3所表示的。
第四行及第五行: 如果沒有接收到數(shù)據(jù),則跳出循環(huán),繼續(xù)監(jiān)聽。
if not data:
break
第六行 sock.send(('[%s] %s' %(ctime(),data)).encode()),向客戶端發(fā)送轉(zhuǎn)換格式(encode)后的數(shù)據(jù)。
數(shù)據(jù)包括兩部分,第一部分是ctime(),表示以字符串形式表示的時(shí)間,data表示變量中存的信息.前面還有一部分'[%s] %s'中的%s格式化字符串,形成需要的輸出格式。
最后一句sock.close(),關(guān)閉套接字。
這樣服務(wù)器端就完成了。我們?cè)賮?lái)看客戶端。
import socket
HOST = '127.0.0.1'
PORT = 8080
BUFSIZE = 1024
ADDR=(HOST,PORT)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
這部只解釋幾句,HOST = ‘127.0.0.1' ,PORT = 8080,這兩句是服務(wù)器端的IP地址和端口號(hào)。
sock.connect((HOST, PORT)) 這一句是利用創(chuàng)建好的socket套接字主動(dòng)初始化TCP服務(wù)器連接,就是向服務(wù)器提出申請(qǐng),服務(wù)器端用sock.accept()接受請(qǐng)求。
這一句執(zhí)行完之后,通信就建立起來(lái)了,在服務(wù)器端會(huì)執(zhí)行print('…connected from:',addr),結(jié)果如圖5圈2所示。
while True:
data = input('> ')
if not data:
break
sock.send(data.encode())
data = sock.recv(BUFSIZE).decode()
if not data:
break
print(data)
sock.close()
接下來(lái)進(jìn)入永真循環(huán),先是input函數(shù),輸出> 后等待輸入,如圖2所示。例如輸入hi,server,如圖4的圈1,然后后兩句是
if not data:
break
如果沒有輸入,則跳出循環(huán)。
第五行sock.send(data.encode()),將輸入的數(shù)據(jù)轉(zhuǎn)換格式后將數(shù)據(jù)發(fā)送給服務(wù)器端,這時(shí)把hi,server發(fā)送給服務(wù)器端,服務(wù)器用data =sock.recv(BUFSIZE).decode()來(lái)接收,同時(shí)用print(‘date=',data)打印出來(lái),結(jié)果如5的圈3所示。
這時(shí),服務(wù)器會(huì)繼續(xù)執(zhí)行sock.send(('[%s] %s' %(ctime(),data)).encode()),把當(dāng)前的時(shí)間和數(shù)據(jù)發(fā)送給客戶端。
而在客戶端,執(zhí)行data = sock.recv(BUFSIZ).decode(),所以客戶端會(huì)接收到相應(yīng)的數(shù)據(jù),并且打印出來(lái),結(jié)果如圖4的圈2所示。
以上就是Socket套接字的TCP通信。
到此這篇關(guān)于python基礎(chǔ)之Socket套接字詳解的文章就介紹到這了,更多相關(guān)python Socket詳解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- Python socket 套接字實(shí)現(xiàn)通信詳解
- python粘包問(wèn)題及socket套接字編程詳解
- 詳解python3中socket套接字的編碼問(wèn)題解決
- python socket網(wǎng)絡(luò)編程步驟詳解(socket套接字使用)
- Python基礎(chǔ)之Socket通信原理
- python實(shí)現(xiàn)socket簡(jiǎn)單通信的示例代碼
- python和websocket構(gòu)建實(shí)時(shí)日志跟蹤器的步驟
- 用Python進(jìn)行websocket接口測(cè)試