原理和我那篇C#相同
只是因為Python的編碼工具和C#差異挺大的,所以實作細節上不太一樣
Server.py
import socket
import threading
import struct
class Server:
def __init__(self, port):
# https://docs.python.org/3.9/library/socket.html
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# IP設定0.0.0.0的原因可參考這篇
# https://superuser.com/questions/949428/whats-the-difference-between-127-0-0-1-and-0-0-0-0
self.server.bind(('0.0.0.0', port))
self.server.listen(1) # 傳入的參數代表允許多少個目標連入
# 因為程式會在等待連線中停住,所以需要使用Thread等非同步方式去處理
self.threadAccept = threading.Thread(target=self.Accept)
self.threadAccept.start()
self.FLAG_RECEIVE = False # 用來控制是否要停止接收資料
def Accept(self):
print('Wait Connect...')
self.socket, self.address = self.server.accept()
print(f'Conneted by {self.address}')
self.server.close() # 若不需要再接收其他連線則可以關掉server這個socket物件
# 準備接收資料
self.FLAG_RECEIVE = True
self.threadReceive = threading.Thread(target=self.Receive)
self.threadReceive.start()
def Receive(self):
while(self.FLAG_RECEIVE):
# 因為Client端分兩次傳送資料,所以這邊也要分兩次接收
# unpack詳情可看這篇: https://cloud.tencent.com/developer/article/1406350
data = self.socket.recv(4) # int是4byte
msg_len = struct.unpack('i', data)[0] # 解碼後是tuple型態,由於只有單個資料,所以這邊用[0]
data = self.socket.recv(msg_len)
msg = struct.unpack(str(msg_len)+'s', data)[0] #'同上面的unpack
print('Receive: ' + msg.decode('utf-8'))
def Close(self):
self.FLAG_RECEIVE = False
self.socket.close()
if __name__ == '__main__':
server = Server(8000)
input() # 按下Enter結束程式
server.Close()
Client.py
import socket
import threading
import struct
class Client:
def __init__(self, ip, port):
# https://docs.python.org/3.9/library/socket.html
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((ip, port))
self.FLAG_SEND = True
self.thread = threading.Thread(target=self.Send)
self.thread.start()
def Send(self):
while(self.FLAG_SEND):
msg = 'Hello Server!!'.encode('utf-8') # string to byte array
msg_len = int(len(msg)) # 強制轉為int類型,大小是4 byte
# 分兩次傳送,先傳遞資料數,再傳遞資料
# pack詳情可看這篇: https://cloud.tencent.com/developer/article/1406350
packet_data = struct.pack('i', msg_len) # 將資料封裝
self.socket.send(packet_data)
packet_data = struct.pack(str(msg_len)+'s', msg) # 將資料封裝
self.socket.send(packet_data)
def Close(self):
self.FLAG_SEND = False
self.socket.close()
if __name__ == '__main__':
client = Client('127.0.0.1', 8000)
input() # 按下Enter結束程式
client.Close()