Socket通信Python實(shí)現(xiàn)
最近開始看一本非常經(jīng)典的網(wǎng)絡(luò)教程,計(jì)算機(jī)網(wǎng)絡(luò)教程:自頂向下方法捉撮,這本書的是從應(yīng)用層開始寫起怕品,相對于以前坑爹的本科生教程更容易令讀者感興趣,并且循循誘導(dǎo)巾遭,深入淺出肉康,是本難得的網(wǎng)絡(luò)教程。
第二章有一個編程作業(yè)就是實(shí)現(xiàn)簡單的Socket通信灼舍,這篇文章結(jié)合UDP和TCP的原理講一下相關(guān)代碼吼和。值得注意的是文章中的代碼使用的Python3.6的版本,所有的網(wǎng)絡(luò)傳輸默認(rèn)傳遞的是二進(jìn)制比特流骑素,因此采用了utf-8進(jìn)行編碼
1.Socket
Socket中文就是套接字炫乓,它是進(jìn)程和網(wǎng)絡(luò)之間的通信接口,可以簡單認(rèn)為它就是一個API献丑,一個Socket由IP
+Port
構(gòu)成末捣,兩個進(jìn)程間如果需要通過網(wǎng)絡(luò)通信,那么他們各自需要通過相同的Socket從網(wǎng)絡(luò)中讀/寫數(shù)據(jù)创橄,具體過程可以從下圖了解箩做。
2.UDP
首先,UDP是一個面向無連接的傳輸層協(xié)議妥畏,它在服務(wù)器端和客戶端的功能沒有太大區(qū)別邦邦,只用創(chuàng)建一個套接字,按照預(yù)定的業(yè)務(wù)或邏輯從套接字中進(jìn)行讀寫醉蚁。文章中UDP通信目的是利用客戶端發(fā)送小寫字符串燃辖,服務(wù)端將該字符串轉(zhuǎn)換為大寫并返回。
2.1 UDP客戶端代碼
按照UDP通信流程圖馍管,首先創(chuàng)建了套接字郭赐,設(shè)定服務(wù)端的IP地址和端口號薪韩,并組成Socket确沸。再通過AF_INET設(shè)定網(wǎng)絡(luò)協(xié)議為IPv4,SOCK_DGRAM設(shè)置傳輸層使用UDP俘陷。
from socket import *
class UdpClient:
serverName = '127.0.0.1'
serverPort = 12000
socketAddress = (serverName, serverPort)
def __init__(self):
#define the type of socket is IPv4 and Udp
self.clientSocket = socket(AF_INET, SOCK_DGRAM)
while True:
message = input("Input a lowercase sentence\n")
self.clientSocket.sendto(message.encode('utf-8'), self.socketAddress)
returnMessage, serverAddress = self.clientSocket.recvfrom(2048)
if not returnMessage:
break
print("The peersocket is: %s:%s" %(serverAddress[0], serverAddress[1]))
print("The return message is: %s" %returnMessage.decode('utf-8'))
if __name__ == '__main__':
client = UdpClient()
2.2 UDP服務(wù)端代碼
服務(wù)端代碼和客戶端沒有太多區(qū)別罗捎。
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.bind(('',serverPort))
print('Waiting for connection...')
while True:
message, clientAddress = serverSocket.recvfrom(2048)
print('Receive Message: %s' %message.decode('utf-8'))
modifiedMessage = message.decode('utf-8').upper()
serverSocket.sendto(modifiedMessage.encode('utf-8'), clientAddress)
3.TCP
TCP是面向連接的傳輸協(xié)議,需要三次握手建立連接拉盾,應(yīng)用需要綁定Socket桨菜。相對于UDP多了listen
、accept
和connect
的過程。
3.1 TCP客戶端
客戶端代碼如下倒得,主要實(shí)現(xiàn)從服務(wù)端返回當(dāng)前時鐘的功能泻红,與UDP的代碼相差不大,因?yàn)槭敲嫦蜻B接霞掺,所有需要多一個connect的過程:
from socket import *
serverName = '127.0.0.1'
serverPort = 11000
BUFSIZ = 1024
ADDR = (serverName,serverPort)
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect(ADDR)
while True:
data = "client message"
if not data:
break
clientSocket.send(data.encode('utf-8'))
returnData = clientSocket.recv(BUFSIZ)
if not returnData:
break
print('Return time is:%s' %returnData.decode('utf-8'))
clientSocket.close()
3.2 TCP服務(wù)端
服務(wù)端主要做了以下工作谊路,首先綁定一個套接字,用于監(jiān)聽客戶端的服務(wù)請求菩彬,同時這里利用listen(5)
設(shè)定最大的tcp連接數(shù)為5缠劝,然后進(jìn)入循環(huán),每次循環(huán)記錄當(dāng)前客戶端的socket骗灶,并處理相應(yīng)地業(yè)務(wù):
from socket import *
from time import ctime
host = ''
port = 11000
ADDR = (host, port)
BUFSIZ = 1024
tcpSocket = socket(AF_INET, SOCK_STREAM)
tcpSocket.bind(ADDR)
#set the max number of tcp connection
tcpSocket.listen(5)
while True:
print('waiting for connection...')
clientSocket, clientAddr = tcpSocket.accept()
print('conneted form: %s' %clientAddr[0])
while True:
try:
data = clientSocket.recv(BUFSIZ)
except IOError as e:
print(e)
clientSocket.close()
break
if not data:
break
returnData = ctime()+data.decode('utf-8')
clientSocket.send(returnData.encode('utf-8'))
clientSocket.close()
tcpSocket.close()
這里是需要先運(yùn)行server的code惨恭,再執(zhí)行client的code:
? Py python3 TcpServer.py
? Py python3 TcpClient.py
Client log:
Return time is:Sun Dec 16 17:04:10 2018client message
Return time is:Sun Dec 16 17:04:10 2018client message
...
小結(jié)
Socket是網(wǎng)絡(luò)通信中的一項(xiàng)重要技術(shù),也是一種進(jìn)程通信的手段耙旦,這里列出了一個簡單的實(shí)現(xiàn)版本脱羡,有時間希望可以結(jié)合多線程完善該功能。