本文簡要介紹對套接字的網絡編程。套接字是結算及網絡數據結構,體現的是“通信端點”的概念。網絡應用程序在進行任何通信之前,必須先創建套接字。
一、主要函數介紹:
Python中的網絡編程,主要使用socket模塊的函數。
socket =》創建套接字對象,socket(s ocket_family , socket_type , protocol =0)
服務器端的方法:
bind =》綁定地址到套接字
listen =》啓動TCP監聽
accept =》 接受客戶端連接
客戶端的方法:
connect =》初始化一個TCP服務連接
數據發送和接收:
recv =》接收數據
send =》發送數據
二、服務器端簡單的socket編程
1、創建socket:
import socket
from time import ctime
HOST = ''
PORT = 21567
BUFSIZE = 100
#一般取1024,可以自己根據需要調整。
ADDR = (HOST, PORT)
# 創建socket並監聽本地端口.
tcpServerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpServerSock.bind(ADDR)
tcpServerSock.listen(5)
2、接受客戶端連接,接收併發送數據
print("等待連接......")
tcpClientSock, addr = tcpServerSock.accept()
print("... 客戶端的地址爲:", addr)
while True:
#內循環,處理客戶端數據的發送和接收。
data = tcpClientSock.recv(BUFSIZE)
if not data:
break
recData = data.decode() #二進制數據轉換爲字符串。默認utf-8
print("從客戶端收到的數據:", recData)
sendData = "[%s] %s"%(ctime(), recData)
tcpClientSock.send(sendData.encode())
tcpClientSock.close()
tcpServerSock.close()
三、客戶端socket編程
1、建立TCP連接
import socket
HOST = 'LOCALHOST'
PORT = 21567
BUFSIZE = 100
ADDR = (HOST, PORT)
tcpClientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpClientSock.connect(ADDR)
2、定義發送函數
def send01(sock,
msg):
# 在網絡不忙的時候,send函數每一次都會將全部的數據發送出去,一幫情況下會工作的很好。
sock.send(msg.encode())
3、發送數據到服務器並接收服務器的數據
data = input('> ')
if not data:
break
sendtotal(tcpClientSock, data)
data = tcpClientSock.recv(BUFSIZE)
if not data:
break
recData = data.decode() #將二進制數據轉換爲字符串數據。
print("從服務器上收到的數據:%s"%(recData))
4、網絡繁忙時發送數據的方法
def sendtotal(sock,
msg):
#判斷send發送的字節數, 直到全部發送完。
totalsent = 0
data = msg.encode()
datalen = len(data)
while totalsent < datalen:
sent = sock.send(data[totalsent:])
if sent == 0:
raise RuntimeError("socket連接中斷")
totalsent = totalsent + sent
四、併發socket編程
上述簡單的socket編程方法,最多隻能處理一個客戶端的連接。python具有強大的線程處理能力,我們可以將線程與socket編程混合到一起,就可以同時處理多個客戶端的連接。
1、自定義socket線程類:
class SocketThread(threading.Thread):
"""自定義socket線程類"""
def __init__(self,
sock):
threading.Thread.__init__(self)
self.sock = sock
def run(self):
while True:
# 內循環,處理客戶端數據的發送和接收。
data = self.sock.recv(BUFSIZE)
if not data:
break
recData = data.decode() # 二進制數據轉換爲字符串。默認utf-8
print("從客戶端收到的數據:", recData)
sendData = "[%s] %s" % (ctime(), recData)
self.sock.send(sendData.encode())
self.sock.close()
2、SocketThread的使用
def client_thread(sock):
t = SocketThread(sock)
return t
pass
#外循環,等待客戶端連接
while True:
print("等待連接......")
tcpClientSock, addr = tcpServerSock.accept()
print("... 客戶端的地址爲:", addr)
ct = client_thread(tcpClientSock)
ct.start() #啓動線程
5、非阻塞socket編程
在使用線程來處理多個socket連接的問題時,受限於機器資源,線程是昂貴且有限的資源,同時處理的socket連接數畢竟有限。
下面就介紹一下python中非阻塞socket是如何處理的。
1、簡介:
非阻塞socket編程主要依賴於select模塊,該模塊提供了特定平臺的I/O監視函數。最輕便的方法就是POSIX功能的select()函數,在unix和windows平臺上都可用。
readable, writable, exceptional = select.select(inputs, outputs, inputs)
select方法會返回三個socket列表,分別爲讀列表,寫列表,異常列表,然後分別對這三個列表的socket進行處理。
2、select方法的使用:
import socket
import select
import queue
from time import ctime
HOST = ''
PORT = 21567
BUFSIZE = 1024
#一般取1024,可以自己根據需要調整。
ADDR = (HOST, PORT)
# 創建socket並監聽本地端口.
tcpServerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpServerSock.setblocking(0)
tcpServerSock.bind(ADDR)
tcpServerSock.listen(5)
# 準備讀數據的socket列表。
inputSockets = [tcpServerSock]
#準備發送數據的socket列表。
outputSockets = []
#輸出的消息隊列。
message_queues = {}
print("等待連接......")
readable, writable, exceptional = select.select(inputSockets, outputSockets, inputSockets)
3、對讀socket列表的處理:
for s in readable:
#處理讀的socket
if s is tcpServerSock:
clientConnection, addr = tcpServerSock.accept()
print("... 客戶端的地址爲:", addr)
clientConnection.setblocking(0)
inputSockets.append(clientConnection) #放到讀取數據列表中。
#每一個connection一個發送數據的隊列。
message_queues[clientConnection] = queue.Queue()
else:
data = s.recv(BUFSIZE)
if data:
print("從%s接收到數據%s" % (s.getpeername(), data.decode()))
message_queues[s].put(data)
if s not
in outputSockets:
outputSockets.append(s)
else:
print("關閉客戶端%s,沒有讀取到數據." % (addr))
if s in outputSockets:
outputSockets.remove(s)
inputSockets.remove(s)
s.close()
#刪除當前socket對應的消息隊列。
del message_queues[s]
4、對寫socket列表的處理:
#處理數據發送隊列。
for s in writable:
try:
next_msg = message_queues[s].get_nowait()
except queue.Empty:
print("%s的輸出隊列爲空" % ("ddddd"))
outputSockets.remove(s)
else:
print("發送數據 %s 到 %s" % (next_msg, s.getpeername()))
s.send(next_msg)
5、對異常socket列表的處理:
for s in exceptional:
print("與%s的通信產生異常,連接將被斷開"%(s.getpeername()))
inputSockets.remove(s)
if s in outputSockets:
outputSockets.remove(s)
s.close()
del message_queues[s]
備註:
完整源代碼可以搜索:python網絡編程