基礎(chǔ)Python的socket編本入門介紹
這篇文章主要介紹了最基礎(chǔ)的Python的socket編程入門教程,包括最基本的發(fā)送和接受信息等內(nèi)容,需要的朋友可以參考下
本文介紹使用Python進(jìn)行Socket網(wǎng)絡(luò)編程,假設(shè)讀者已經(jīng)具備了基本的網(wǎng)絡(luò)編程知識和Python的基本語法知識,本文中的代碼如果沒有說明則都是運(yùn)行在Python 3.4下。
Python的socket功能封裝在socket庫中,要使用socket,記得先import socket,socket庫的詳細(xì)介紹參見官方文檔。
創(chuàng)建Socket
首先創(chuàng)建一個socket,使用socket庫中得socket函數(shù)創(chuàng)建。
import socket
# create an INET, STREAM socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
例子中創(chuàng)建了一個TCP socket,socket.socket函數(shù)的前兩個參數(shù)的默認(rèn)值是socket.AF_INET和socket.SOCK_STREAM,創(chuàng)建TCP socket時可以直接寫成socket.socket()。
連接服務(wù)器
使用socket的connect函數(shù)連接到服務(wù)器,以下幾種參數(shù)都是合法的。
s.connect(('localhost', 8000))
s.connect(('127.0.0.1', 8000))
s.connect(('www.baidu.com', 80))
發(fā)送數(shù)據(jù)
發(fā)送數(shù)據(jù)有兩個方法send和sendall,send不能保證所有的數(shù)據(jù)都發(fā)送完了,它會返回已發(fā)送數(shù)據(jù)的長度,程序要循環(huán)發(fā)送數(shù)據(jù)直到所有數(shù)據(jù)都已發(fā)送完畢。
def mysend(s, msg):
total_len = len(msg)
total_sent = 0
while total_sent < total_len:
sent = s.send(msg[total_sent:])
if sent == 0:
raise RuntimeError("socket connection broken")
total_sent += sent
sendall能夠保證所有的數(shù)據(jù)都已發(fā)送完畢,除非發(fā)送過程中出現(xiàn)了錯誤,它實(shí)際上也是循環(huán)發(fā)送數(shù)據(jù)直到所有數(shù)據(jù)發(fā)送完成。
這里還要講一個需要特別注意的地方,從一個例子開始吧:
import socket
s = socket.socket()
s.connect(('www.baidu.com', 80))
s.sendall('test')
都是上面講過的東西,沒什么特別的,分別在Python 2和Python 3中執(zhí)行以上的代碼,結(jié)果是:
# Python 2.7
>>> import socket
>>> s = socket.socket()
>>> s.connect(('www.baidu.com', 80))
>>> s.sendall('test')
Python 2中執(zhí)行成功。
# Python 3.4
>>> import socket
>>> s = socket.socket()
>>> s.connect(('www.baidu.com', 80))
>>> s.sendall('test')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' does not support the buffer interface
Python 3中卻發(fā)生了異常。
同樣的代碼換個環(huán)境卻不能執(zhí)行了,我沒有寫錯呀,怒砸電腦。好吧,你確實(shí)沒寫錯,是環(huán)境變了,導(dǎo)致這個結(jié)果的變化請移步官方的說明。
接收數(shù)據(jù)
使用recv函數(shù)接收數(shù)據(jù):
data = s.recv(4096)
在Python 3中返回的是bytes對象,在Python 2中返回的是string。注意函數(shù)返回的數(shù)據(jù)長度是小于或者等于參數(shù)指定的長度的,要接收到指定長度的數(shù)據(jù),需要循環(huán)接收數(shù)據(jù)。
def myreceive(s, msglen):
chunks = []
bytes_recd = 0
while bytes_recd < msglen:
chunk = s.recv(min(msglen - bytes_recd, 2048))
if chunk == b'':
raise RuntimeError("socket connection broken")
chunks.append(chunk)
bytes_recd = bytes_recd + len(chunk)
return b''.join(chunks)
關(guān)閉連接
當(dāng)連接不再需要時可以使用close關(guān)閉socket連接,關(guān)閉后的連接不能再進(jìn)行任何操作。當(dāng)一個socket被回收時會自動關(guān)閉,但是不要依賴這種機(jī)制,不需要socket時就主動的close。
服務(wù)端
服務(wù)端程序執(zhí)行的步驟:
1. 創(chuàng)建服務(wù)端socket
1. 將服務(wù)端socket綁定到指定的地址和端口
1. 監(jiān)聽連接
1. 接受客戶端連接
1. 處理客戶端的數(shù)據(jù)
1. 關(guān)閉客戶端連接
一個簡單的echo server示例:
import socket
HOST = ''
PORT = 10022
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(10)
conn, addr = s.accept()
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
conn.close()
客戶端程序:
import socket
HOST = 'localhost'
PORT = 10022
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(b'hello socket')
data = s.recv(1024)
print('Received', repr(data))
s.close()
錯誤處理
socket處理過程中發(fā)生錯誤會拋出異常,socket相關(guān)的異常有:
- socket.error
- socket.herror
- socket.gaierror
- socket.timeout
import socket
HOST = None
PORT = 10022
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(10)
except: socket.error as msg:
print(msg)
更多信息請查看IT技術(shù)專欄