1.客户端与服务端的地址
客户端:192.168.99.1
服务端:192.168.56.1
2.大体流程
整个流程主要分为三个步骤:客户端向服务端发送数据、服务端开启子线程向客户端发送数据、客户端与服务端子线程进行交互
3.分析三个步骤
(1)客户端向服务端发送数据
客户端向服务端发送数据的目的是让服务端建立与客户端交互的客户端镜像。
如客户端通过 socket.sendto(data, addr) 函数来向服务端发送数据 data ,服务端通过 socket.recvfrom(1024) 来监听客户端的数据,会返回元组**(data, addr)**。
此时,addr 的内容为**(‘192.168.56.1’, 67458)**,ip 地址为服务端地址,端口为服务端随机开辟的一个端口,这个 addr 可以认为是客户端在服务端的镜像,服务端可以通过 addr 向客户端发送数据。
(2)服务端开启子线程向客户端发送数据
服务端的 socket.recvfrom(1024) 是阻塞的,当接收到客户端数据将会向下执行,此时开启子线程,传入客户端镜像地址 addr,并新建一个 socket 套接字,然后使用新建的套接字向客户端发送数据 socket.sendto(data,addr) ,此时客户端使用 socket.recvfrom(1024) 来接收,与服务器同理,会在本地创建一个服务端镜像,镜像地址为函数返回的 addr。
(3)客户端与服务端子线程进行交互
此时,客户端使用 recvfrom() 接收数据,服务端使用 recv() 接收数据。
4.测试代码
客户端测试代码:
import socket
import threading
import time
ss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# s.bind(('192.168.56.1', 1234))
Id = input("请输入本机的ID号:")
msg = Id + ":hello"
ss.sendto(msg.encode('utf-8'), ('192.168.56.1', 1234))
server_addr = []
def printReceived():
while True:
msg, addr = ss.recvfrom(1024)
server_addr.append(addr)
print(addr)
print("\n从服务端接收到数据:" + msg.decode('utf-8'))
print("请输入要发送的数据:", end="")
t = threading.Thread(target=printReceived)
t.start()
while True:
msg = input("请输入要发送的数据:")
msg = Id + ":" + msg
ss.sendto(msg.encode('utf-8'), server_addr[0])
服务端测试代码:
import socket
import threading
import time
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('192.168.56.1', 1234))
addrList = []
def acceptedClient(d, address):
# print(d)
if address not in addrList:
addrList.append(address)
clientMirror = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
clientMirror.sendto('hello'.encode('utf-8'), address)
while True:
print(clientMirror.recv(1024).decode('utf-8'))
clientMirror.sendto('ok'.encode('utf-8'), addrList[0])
while True:
d, addr = s.recvfrom(1024)
t = threading.Thread(target=acceptedClient, args=(d, addr, ))
t.start()