標籤:
通訊端:通訊端點
什麼是通訊端?
書上說的連接埠是資料結構和I/O緩衝區”是指硬體連接埠,網路編程裡的連接埠可以理解為應用程式的ID。
說得形象點,通訊端就類似我們人類的門
我們開啟門,通過門外面的人可以進來
我們推開門,裡面的人也可以出去
同樣,外面的資料可以通過socket把它儲存在本地機器的緩衝區裡等待本地機器接收
本地機器的資料可以通過socket放在緩衝區裡等待發送到對方機器上
當我們把門給關上時,就拒絕了和外面世界的交往。
通訊端是一種具有之前所說的“通訊端點”概念的電腦網路資料結構。網路化的應用程式在開始任何通
訊之前都必需要建立通訊端。就像電話的插口一樣,沒有它就完全沒辦法通訊。
通訊端有兩種,分別是基於檔案型的和基於網路型的。
基於檔案型的:
Unix 通訊端是我們要介紹的第一個通訊端家族。其“家族名”為AF_UNIX,由於兩個進程都運行在同一台
機器上,而且這些通訊端是基於檔案的。所以,它們的底層結構是由檔案系統來支援的。這樣做相當有道
理,因為,同一台電腦上,檔案系統的確是不同的進程都能訪問的。
基於網路型的
它有自己的家族名字:AF_INET,或叫“地址家族:Internet”。
Python 只支援AF_UNIX,AF_NETLINK,和AF_INET 家族。由於我們只關心網路編程,所以在本章的大部分
時候,我們都只用AF_INET。
通訊端的類型只有兩種。一種是連線導向的通訊端,即在通訊之前一定要建立一條串連,就像跟朋友打電
話時那樣。這種通訊方式也被稱為“虛電路”或“流通訊端”。連線導向的通訊方式提供了順序的,可靠
的,不會重複的資料轉送,而且也不會被加上資料邊界。這也意味著,每一個要發送的資訊,可能會被拆
分成多份,每一份都會不多不少地正確到達目的地。然後被重新按順序拼裝起來,傳給正在等待的應用程
序。
建立通訊端:
from socket import *
tcpsock=socket(AF_INET,SOCK_STREAM)
udpsock=socket(AF_INET,SOCK_DGRAM)
通訊端對象(內建)方法
函數 描述
伺服器端通訊端函數
s.bind() 綁定地址(主機,連接埠號碼對)到通訊端
s.listen() 開始TCP 監聽
s.accept() 被動接受TCP 客戶的串連,(阻塞式)等待串連的到來
用戶端通訊端函數
s.connect() 主動初始化TCP 伺服器串連
s.connect_ex() connect()函數的擴充版本,出錯時返回出錯碼,而不是拋異常
公用用途的通訊端函數
s.recv() 接收TCP 資料
s.send() 發送TCP 資料
s.sendall() 完整發送TCP 資料
s.recvfrom() 接收UDP 資料
s.sendto() 發送UDP 資料
s.getpeername() 串連到當前通訊端的遠端的地址
s.getsockname() 當前通訊端的地址
s.getsockopt() 返回指定通訊端的參數
s.setsockopt() 設定指定通訊端的參數
s.close() 關閉通訊端
Blocking-Oriented Socket Methods
s.setblocking() 設定通訊端的阻塞與非阻塞模式
s.settimeout() 設定阻塞通訊端操作的逾時時間
s.gettimeout() 得到阻塞通訊端操作的逾時時間
面向檔案的通訊端的函數
s.fileno() 通訊端的檔案描述符
s.makefile() 建立一個與該通訊端關連的檔案
建立一個tcp伺服器的虛擬碼:
ss=socket() #建立伺服器通訊端
ss.bind() #把地址綁定到通訊端上
ss.listen() #監聽連結
inf_loop #伺服器無線迴圈
cs=ss.accept() #接受客戶的連結
comm_loop #通訊迴圈
cs.recv()/cs.send() #對話(接受與發送)
cs.close() #關閉客戶通訊端
ss.close() #關閉伺服器通訊端(可選)
會建立一個TCP 伺服器程式:
from socket import *
from time import ctime
HOST=‘‘
PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)
tcpSerSock=socket(AF_INET,SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)
while True:
print ‘waiting for connection...‘
tcpCliSock,addr=tcpSerSock.accept()
print ‘... connected from:‘,addr
while True:
data=tcpCliSock.rece(BUFSIZ)
if not data:
break
tcpCliSock.send(‘[%s]%s‘%(ctime(),data))
tcpCliSock.close()
tcpSerSock.close()
建立TCP 用戶端:
虛擬碼:
cs = socket() # 建立客戶通訊端
cs.connect() # 嘗試串連伺服器
comm_loop: # 通訊迴圈
cs.send()/cs.recv() # 對話(發送/接收)
cs.close() # 關閉客戶通訊端
執行個體:
from socket import *
from time import ctime,sleep
HOST=‘localhost‘
PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)
tcpCliSock=socket(AF_INET,SOCK_STREAM)
tcpCliSock.connect(ADDR)
while True:
data=raw_input(‘>‘)
if not data:
break
tcpCliSock.send(data)
sleep(6)
data=tcpCliSock.recv(BUFSIZ)
if not data:
break
print data
tcpCliSock.close()
運行我們的用戶端與伺服器程式,先運行伺服器端再運行用戶端,因為伺服器端是被動的,他要在那裡等
待著。
socket.error: [Errno 10054]說明伺服器端出現了error,socket.error: [Errno 10053]用戶端出現了問
題
建立一個UDP 伺服器:
ss = socket() # 建立一個伺服器通訊端
ss.bind() # 綁定伺服器通訊端
inf_loop: # 伺服器無限迴圈
cs = ss.recvfrom()/ss.sendto() # 對話(接收與發送)
ss.close() # 關閉伺服器通訊端
執行個體:
from socket import *
from time import ctime,sleep
HOST=‘localhost‘
PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)
tcpCliSock=socket(AF_INET,SOCK_STREAM)
tcpCliSock.connect(ADDR)
while True:
data=raw_input(‘>‘)
if not data:
break
tcpCliSock.send(data)
sleep(6)
data=tcpCliSock.recv(BUFSIZ)
if not data:
break
print data
tcpCliSock.close()
建立一個UDP 用戶端:
虛擬碼:
cs = socket() # 建立客戶通訊端
comm_loop: # 通訊迴圈
cs.sendto()/cs.recvfrom() # 對話(發送/接收)
cs.close() # 關閉客戶通訊端
執行個體:
from socket import *
HOST=‘localhost‘
PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)
udpCliSock=socket(AF_INET,SOCK_DGRAM)
while True:
data=raw_input(‘>‘)
if not data:
break
udpCliSock.sendto(data,ADDR)
data,ADDR=udpCliSock.recvfrom(BUFSIZ)
if not data:
break
print data
udpCliSock.close
通訊端模組屬性:
屬性名稱字 描述
資料屬性
AF_UNIX, AF_INET, AF_INET6a Python 支援的通訊端家族
SO_STREAM, SO_DGRAM 通訊端類型 (TCP = 流, UDP = 資料報)
has_ipv6b 表示是否支援IPv6 的標誌變數
異常
error 通訊端相關錯誤
herrora 主機和地址相關的錯誤
gaierrora 地址相關的錯誤
timeoutb 逾時
函數
socket() 用指定的地址家族,通訊端類型和協議類型(可選)建立一個通訊端對象
socketpair()c 用指定的地址家族,通訊端類型和協議類型(可選)建立一對通訊端對象
fromfd() 用一個已經開啟的檔案描述符建立一個通訊端對象資料屬性
ssl()d 在通訊端初始化一個安全通訊端層(SSL)。不做認證驗證。
getaddrinfo()a 得到地址資訊
getfqdn()e 返回完整的域的名字
gethostname() 得到當前主機名稱
gethostbyname() 由主機名稱得到對應的ip 地址
gethostbyname_ex() gethostbyname()的擴充版本,返回主機名稱,主機所有的別名和
IP 位址列表。
gethostbyaddr() 由IP 位址得到DNS 資訊,返回一個類似gethostbyname_ex()
的3 元組。
getprotobyname() 由協議名(如‘tcp‘)得到對應的號碼。
getservbyname()/ 由服務名得到對應的連接埠號碼或相反
getservbyport() 兩個函數中,協議名都是可選的。
ntohl()/ntohs() 把一個整數由網路位元組序轉為主機位元組序
htonl()/htons() 把一個整數由主機位元組序轉為網路位元組序
inet_aton()/ 把IP 位址轉為32 位整型,以及反向函數。(僅對IPv4 地址有效)
inet_ntoa()
inet_pton()/ 把IP 位址轉為二進位格式以及反向函數。(僅對IPv4 地址有效)
inet_ntop()b
getdefaulttimeout()/ 得到/設定預設的通訊端逾時時間,單位秒(浮點數)
setdefaulttimeout()
*SocketServer 模組
用*SocketServer 模組簡化上面的例子:
tcp server:
from SocketServer import TCPServer as TCP, StreamRequestHandler as SRH
from time import ctime
HOST=‘‘
PORT=21567
ADDR=(HOST,PORT)
class MyRequestHandler(SRH):
def handle(self):
print ‘...connected from:‘,self.client_address
self.wfile.write(‘[%s]%s‘%(ctime(),self.rfile.readline()))
tcpServ=TCP(ADDR,MyRequestHandler)
print ‘waiting for connection...‘
tcpServ.serve_forever()
tcp client:
from socket import *
from time import ctime,sleep
HOST=‘localhost‘
核心編程
PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)
while True:
tcpCliSock=socket(AF_INET,SOCK_STREAM)
tcpCliSock.connect(ADDR)
data=raw_input(‘>‘)
if not data:
break
tcpCliSock.send(‘%s\r\n‘%data)
data=tcpCliSock.recv(BUFSIZ)
if not data:
break
print data.strip()
tcpCliSock.close()
Twisted 架構介紹:
Twisted 是一個完全事件驅動的網路架構。它允許你使用和開發完全非同步網路應用程式和協議。
這個模組要單獨安裝,內容也比較多,稍後再仔細研究吧
chapter 16 網路編程