Python Socket Programming

本文介紹使用Python進行Socket網絡編程,假設讀者已經具有了基本的網絡編程知識和Python的基本語法知識,本文中的代碼若是沒有說明則都是運行在Python 3.4下。html

Python的socket功能封裝在socket庫中,要使用socket,記得先import socket,socket庫的詳細介紹參見官方文檔
python

建立Socket

首先建立一個socket,使用socket庫中得socket函數建立。編程

Pythonimport socket

# create an INET, STREAM socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

例子中建立了一個TCP socket,socket.socket函數的前兩個參數的默認值是socket.AF_INETsocket.SOCK_STREAM,建立TCP socket時能夠直接寫成socket.socket()服務器

鏈接服務器

使用socket的connect函數鏈接到服務器,如下幾種參數都是合法的。網絡

Pythons.connect(('localhost', 8000))
s.connect(('127.0.0.1', 8000))
s.connect(('www.baidu.com', 80))

發送數據

發送數據有兩個方法sendsendallsend不能保證全部的數據都發送完了,它會返回已發送數據的長度,程序要循環發送數據直到全部數據都已發送完畢。app

Pythondef 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可以保證全部的數據都已發送完畢,除非發送過程當中出現了錯誤,它實際上也是循環發送數據直到全部數據發送完成。socket

這裏還要講一個須要特別注意的地方,從一個例子開始吧:函數

Pythonimport socket
s = socket.socket()
s.connect(('www.baidu.com', 80))
s.sendall('test')

都是上面講過的東西,沒什麼特別的,分別在Python 2和Python 3中執行以上的代碼,結果是:code

Python# Python 2.7
>>> import socket
>>> s = socket.socket()
>>> s.connect(('www.baidu.com', 80))
>>> s.sendall('test')

Python 2中執行成功。server

Python# 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中卻發生了異常。

一樣的代碼換個環境卻不能執行了,我沒有寫錯呀,怒砸電腦。好吧,你確實沒寫錯,是環境變了,致使這個結果的變化請移步官方的說明

接收數據

使用recv函數接收數據:

Pythondata = s.recv(4096)

在Python 3中返回的是bytes對象,在Python 2中返回的是string。注意函數返回的數據長度是小於或者等於參數指定的長度的,要接收到指定長度的數據,須要循環接收數據。

Pythondef 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)

關閉鏈接

當鏈接再也不須要時能夠使用close關閉socket鏈接,關閉後的鏈接不能再進行任何操做。當一個socket被回收時會自動關閉,可是不要依賴這種機制,不須要socket時就主動的close。

服務端

服務端程序執行的步驟:
1. 建立服務端socket
1. 將服務端socket綁定到指定的地址和端口
1. 監聽鏈接
1. 接受客戶端鏈接
1. 處理客戶端的數據
1. 關閉客戶端鏈接

一個簡單的echo server示例:

Pythonimport 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()

客戶端程序:

Pythonimport 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處理過程當中發生錯誤會拋出異常,socket相關的異常有:
- socket.error
- socket.herror
- socket.gaierror
- socket.timeout

Pythonimport 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)

參考資料

相關文章
相關標籤/搜索