使用套接字進行網絡編程。python
使用socket
模塊的socket()
函數,能夠建立套接字。react
socket
模塊函數要建立套接字,必須使用socket.socket()
函數,語法以下:shell
socket(socket_family, socket_type, protocol=0)
編程
其中,socket_family
是AF_UNIX
或AF_INET
,socket_type
是SOCK_STREAM
或SOCK_DGRAM
。protocol
一般省略,默認爲0
。windows
導入模塊緩存
建立TCP/IP
套接字安全
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
服務器
建立UDP/IP
套接字網絡
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
框架
名稱 | 描述 |
---|---|
s.bind() |
將地址(主機號、端口號對)綁定到套接字上 |
s.listen() |
設置並啓動TCP 監聽器 |
s.accept() |
被動接受TCP 客戶端鏈接,一直等待知道鏈接到達(阻塞) |
名稱 | 描述 |
---|---|
s.connect() |
主動發起TCP 服務器鏈接 |
s.connect_ex() |
connect() 的擴展版本,此時會以錯誤碼的形式返回問題,而不是拋出一個異常 |
名稱 | 描述 |
---|---|
s.recv() |
接收TCP消息 |
s.recv_into() |
接收TCP消息到指定的緩衝區 |
s.send() |
發送TCP消息 |
s.sendall() |
完整地發送TCP消息 |
s.recvfrom() |
接受UDP消息 |
s.recvfrom_into() |
接受UDP消息到指定的緩存區 |
s.sendto() |
發送UDP消息 |
s.getpeername() |
鏈接到套接字(TCP)的遠程地址 |
s.getsockname() |
當前套接字的地址 |
s.getsockopt() |
返回給定套接字選項的指 |
s.setsockopt() |
設置給定套接字選項的值 |
s.shutdown() |
關閉鏈接 |
s.close() |
關閉套接字 |
s.detach() |
在未關閉文件描述符的狀況下關閉套接字,返回文件描述符 |
s.ioctl() |
控制套接字的模式(僅支持windows) |
名稱 | 描述 |
---|---|
s.setblocking() |
設置套接字的阻塞或非阻塞模式 |
s.settimeout() |
設置阻塞套接字操做的超時時間 |
s.gettimeout() |
獲取阻塞套接字操做的超時時間 |
名稱 | 描述 |
---|---|
s.fileno() |
套接字的文件描述符 |
s.makefile() |
建立與套接字關聯的文件對象 |
名稱 | 描述 |
---|---|
s.family |
套接字家族 |
s.type |
套接字類型 |
s.proto |
套接字協議 |
TCP服務器的通常僞代碼。
ss = socket() # 建立服務器套接字 ss.bind() # 套接字與地址綁定 ss.listen() # 監聽鏈接 inf_loop: # 服務器無限循環 cs = ss.accept() # 接收客戶端鏈接 comm_loop: # 通訊循環 cs.recv() / cs.send() # 對話(接受/發送) cs.close() # 關閉客戶端套接字 ss.close() # 關閉服務器套接字(可選)
socket.socket()
函數來建立accept()
函數以後,就開啓了一個簡單的服務器,它會等待客戶端的鏈接,默認狀況下,accept()
是阻塞的,這意味着執行將被暫停,直到一個鏈接到達accept()
)一個獨立的客戶端套接字,用來與即將到來的消息進行交換下面是一個TCP服務器程序,它接受客戶端發送的數據字符串,並將其打上時間戳,並返回給客戶端。
# coding: utf-8 from socket import * from time import ctime HOST = '' # HOST變量是空白,這是對bind()方法的標識,表示它能夠使用任何可用的地址 PORT = 21567 BUFSIZ = 1024 # 緩衝區大小設置爲1KB ADDR = (HOST, PORT) tcpSerSock = socket(AF_INET, SOCK_STREAM) # 分配TCP服務器套接字 tcpSerSock.bind(ADDR) # 將套接字綁定到服務器地址 tcpSerSock.listen(5) # 開啓TCP監聽器的調用,參數是在鏈接被轉接或拒絕以前,傳入鏈接請求的最大數 while True: print('waiting for connection...') tcpCliSock, addr = tcpSerSock.accept() # 被動等待客戶端的鏈接 print('...connected from:', addr) while True: data = tcpCliSock.recv(BUFSIZ) # 等待客戶端發送的消息 if not data: # 若是消息是空白的,意味着客戶端已經退出 break # 跳出對話循環 tcpCliSock.send(bytes('[%s] %s' % (ctime(), data), 'utf-8')) tcpCliSock.close() # 關閉當前客戶端鏈接 # tcpSerSock.close()
TCP客戶端的通常僞代碼。
cs = socket() # 建立客戶端套接字 cs.connect() # 嘗試鏈接服務器 comm_loop: # 通訊循環 cs.send() / cs.recv() # 對話(發送 / 接受) cs.close() # 關閉客戶端套接字
Python代碼實現的TCP客戶端。
# coding: utf-8 from socket import * HOST = '127.0.0.1' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) tcpCliSock = socket(AF_INET, SOCK_STREAM) # 分配TCP客戶端套接字 tcpCliSock.connect(ADDR) # 主動調用並鏈接到服務器 while True: data = input('> ') if not data: break tcpCliSock.send(bytes(data, 'utf-8')) data = tcpCliSock.recv(BUFSIZ) if not data: break print(data.decode('utf-8')) tcpCliSock.close()
服務器端
bovenson@ThinkCentre:~/Git/notes/Python/Code/LearnPythonCode/network_programming$ python3 tsTserv.py waiting for connection... ...connected from: ('127.0.0.1', 35550)
客戶端
bovenson@ThinkCentre:~/Git/notes/Python/Code/LearnPythonCode/network_programming$ python3 tsTclnt.py > Hello [Mon Jun 4 11:20:46 2018] b'Hello' > World [Mon Jun 4 11:20:48 2018] b'World' >
UDP服務器不須要TCP服務器那麼多的設置,由於它們不是面向鏈接的,除了等待傳入的鏈接以外,幾乎不須要作其餘工做。
ss = socket() # 建立服務器套接字 ss.bind() # 綁定服務器套接字 inf_loop(): # 服務器無限循環 cs = ss.recvfrom() / ss.sendto() # 關閉(接受 / 發送) ss.close() # 關閉服務器套接字
UDP服務器和TCP服務器之間的另外一個顯著差別是,覺得數據報套接字是無鏈接的,因此就沒有爲了成功通訊而使一個客戶端鏈接到一個獨立的套接字轉換操做。這些服務器僅僅接受消息並有可能回覆數據。
# coding: utf-8 from socket import * from time import ctime HOST = '' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) udpSerSock = socket(AF_INET, SOCK_DGRAM) udpSerSock.bind(ADDR) while True: print('waiting for message...') data, addr = udpSerSock.recvfrom(BUFSIZ) udpSerSock.sendto('[%s] %s' % (ctime(), data), addr) print('...received from and returned to:', addr) # udpSerSock.close()
客戶端僞代碼以下。
ss = socket() # 建立客戶端套接字 comm_loop: # 通訊循環 cs.sendto() / cs.recvfrom() # 對話(發送 / 接收) cs.close() # 關閉客戶端套接字
Python實現的客戶端代碼。
# coding: utf-8 from socket import * from time import ctime HOST = '' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) udpSerSock = socket(AF_INET, SOCK_DGRAM) udpSerSock.bind(ADDR) while True: print('waiting for message...') data, addr = udpSerSock.recvfrom(BUFSIZ) udpSerSock.sendto(bytes('[%s] %s' % (ctime(), data), 'utf-8'), addr) print('...received from and returned to:', addr) # udpSerSock.close()
客戶端
/usr/bin/python3.5 /home/bovenson/Git/notes/Python/Code/LearnPythonCode/network_programming/tsUclnt.py > Hello b"[Mon Jun 4 12:42:07 2018] b'Hello'" > World b"[Mon Jun 4 12:42:08 2018] b'World'" >
服務端
/usr/bin/python3.5 /home/bovenson/Git/notes/Python/Code/LearnPythonCode/network_programming/tsUserv.py waiting for message... ...received from and returned to: ('127.0.0.1', 59736) waiting for message... ...received from and returned to: ('127.0.0.1', 59736) waiting for message...
注 和TCP不一樣的是,UDP客戶端能夠先於UDP服務器運行。可是TCP服務器必須先於TCP客戶端運行。
socket
模塊屬性屬性名稱 | 描述 |
---|---|
AF_UNIX,AF_INET,AF_INET6,AF_NETLINK,AF_TIPC |
Python 中支持的套接字地址家族 |
SO_STREAM,SO_DGRAM |
套接字類型(TCP=流,UDP=數據報) |
has_ipv6 |
指示是否支持IPv6 的布爾標記 |
名稱 | 描述 |
---|---|
error |
套接字相關錯誤 |
herror |
主機和地址相關錯誤 |
gaierror |
地址相關錯誤 |
timeout |
超時時間 |
名稱 | 描述 |
---|---|
socket() |
以給定的地址家族、套接字類型和協議類型(可選)建立一個套接字對象 |
socketpair() |
以給定的地址家族、套接字類型和協議類型(可選)建立一對套接字對象 |
create_connection() |
常規函數,接受一個地址(主機號,端口號)對,返回套接字對象 |
fromfd() |
以一個打開的文件描述符建立一個套接字對象 |
ssl() |
經過套接字啓動一個安全套接字層鏈接;不執行證書驗證 |
getaddrinfo() |
獲取一個五元組序列形式的地址信息 |
getnameinfo() |
給定一個套接字地址,返回(主機號,端口號)二元組 |
getfqn() |
返回完整的域名 |
gethostname() |
返回當前主機名 |
gethostbyname() |
將一個主機名映射到它的IP地址 |
gethostbyname_ex() |
gethostname() 的擴展版本,它返回主機名、別名主機集合和IP地址列表 |
gethostbyaddr() |
將一個IP地址映射到DNS信息:返回與gethostbyname_ex() 相同的3元組 |
getprotobyname() |
將一個協議名(如tcp )映射到一個數字 |
getservbyname()/getservbyport() |
將一個服務名映射到一個端口號,或者反過來;對於任何一個函數來講,協議名都是可選的 |
ntohl()/ntohs() |
未來自網絡的整數轉換爲主機字節順序 |
htonl()/htons() |
未來自主機的整數轉換爲網絡字節順序 |
inet_aton()/inet_ntoa() |
將IP地址八進制字符串轉換爲32位的包格式,或者反過來(僅用於IPv4地址) |
inet_pton()/inet_ntop() |
將IP地址字符串轉換成打包的二進制格式,或者反過來(同時適用於IPv4和IPv6地址) |
getdefaulttimeout()/setdefaulttimeout() |
以秒(浮點數)爲單位返回默認套接字超時時間;以秒(浮點數)爲單位設置默認套接字超時時間 |
SocketServer
模塊SocketServer
是標準庫中的一個高級模塊,它的目標是簡化不少樣板代碼,它們是建立網絡客戶端和服務器所需必須的代碼。
類 | 描述 |
---|---|
BaseServer |
包含核心服務器功能和mix-in 類的鉤子;僅用於推導,這樣不會建立這個類的實例;能夠用TCPServer 和UDPServer 建立類的實例 |
TCPServer/UDPServer |
基礎的網絡同步TCP/UDP 服務器 |
UnixStreamServer/UnixDatagramServer |
基於文件的基礎同步TCP/UDP 服務器 |
ForkingMixIn/ThreadingMixIn |
核心派出或線程功能;只用做mix-in 類與一個服務器類配合實現一些異步性;不能直接實例化這個類 |
ForkingTCPServer/ForkingUDPServer |
ForkingMixIn 和TCPServer/UDPServer 的組合 |
ThreadingTCPServer/ThreadingUDPServer |
ThreadingMixIn 和TCPServer/UDPServer 的組合 |
BaseRequestHandler |
包含處理服務請求的核心功能;僅僅用於推導,這樣沒法建立這個類的實例;能夠使用StreamRequestHandler 或DatagramRequestHandler 建立類的實例 |
StreamRequestHandler/DatagramRequestHandler |
實現TCP/UDP 服務器的服務處理器 |
事件包括消息的發送和接受。
類定義只包括一個用來接收客戶端消息的事件處理程序,全部其餘的功能都來自使用的SocketServer
類。
SocketServer
TCP服務器# coding: utf-8 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()
MyRequestHandler
做爲SocketServer
中StreamRequestHandler
的一個子類,並重寫了它的handler()
方法。當接收到一個來自客戶端的消息時,就會調用handler()
方法。而StreamRequestHandler
類將輸入和輸出套接字看做相似文件的對象,所以咱們將使用readline()
來獲取客戶端消息,並利用write()
將字符串發送回客戶端。
SocketServer
TCP客戶端# coding: utf-8 from socket import * HOST = 'localhost' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) while True: tcpCliSock = socket(AF_INET, SOCK_STREAM) tcpCliSock.connect(ADDR) data = input('> ') if not data: break tcpCliSock.send(bytes('%s\r\n' % data, 'utf-8')) data = tcpCliSock.recv(BUFSIZ) if not data: break print(data.strip()) tcpCliSock.close()
服務端
/usr/bin/python3.5 /home/bovenson/Git/notes/Python/Code/LearnPythonCode/network_programming/tsTservSS.py waiting for connection... ...connected from: ('127.0.0.1', 36118) ...connected from: ('127.0.0.1', 36120) ...connected from: ('127.0.0.1', 36122)
客戶端
/usr/bin/python3.5 /home/bovenson/Git/notes/Python/Code/LearnPythonCode/network_programming/tsTclntSS.py > a b"[Mon Jun 4 15:34:12 2018] b'a\\r\\n'" > c b"[Mon Jun 4 15:34:13 2018] b'c\\r\\n'" >
Twisted
是一個完整的事件驅動的網絡框架,既能夠使用,也能開發完整的異步網絡應用程序和協議。
Twisted Reactor
TCP服務器# coding: utf-8 from twisted.internet import protocol, reactor from time import ctime PORT = 21567 class TSServProtocol(protocol.Protocol): def connectionMade(self): # 客戶端鏈接到服務器時就會執行 clnt = self.clnt = self.transport.getPeer().host print('...connected from:', clnt) def dataReceived(self, data): # 當服務器收到客戶端經過網絡發送的一些數據時就會調用 dataReceived() 方法 self.transport.write(bytes('[%s] %s' % (ctime(), data), 'utf-8')) factory = protocol.Factory() factory.protocol = TSServProtocol print('waiting for connection...') reactor.listenTCP(PORT, factory) reactor.run()
Twisted Reactor
TCP客戶端# coding: utf-8 from twisted.internet import protocol, reactor HOST = 'localhost' PORT = 21567 class TSClntProtocol(protocol.Protocol): def sendData(self): data = input('> ') if data: print('...sending %s...' % data) self.transport.write(bytes(data, 'utf-8')) else: self.transport.loseConnection() def connectionMade(self): self.sendData() def dataReceived(self, data): print(data) self.sendData() class TSClntFactory(protocol.ClientFactory): protocol = TSClntProtocol clientConnectionLost = clientConnectionFailed = lambda self, connector, reason: reactor.stop() reactor.connectTCP(HOST, PORT, TSClntFactory()) reactor.run()
服務器
/usr/bin/python3.5 /home/bovenson/Git/notes/Python/Code/LearnPythonCode/network_programming/tsTservTW.py waiting for connection... ...connected from: 127.0.0.1
客戶端
/usr/bin/python3.5 /home/bovenson/Git/notes/Python/Code/LearnPythonCode/network_programming/tsTclntTW.py > a ...sending a... b"[Mon Jun 4 16:40:40 2018] b'a'" > b ...sending b... b"[Mon Jun 4 16:40:42 2018] b'b'" >