我们在这篇文章中(用Socket建立简单的数据传输 | Trtyr’s Blog),简单的做到了单次通信,但是在实际中肯定不会这么见简单
首先就是要做到持续通信,而且有可能我们需要多个不同的客户端,然后发现,我们之前写的那个 “玩具” 根本行不通,
一. 多次通信
我们之前的程序,每次传输后,都会自动结束,所以我们要解决这个问题。
我们很容易能想到,加死循环,让它一直连接
先改客户端和先改服务端都一样。我们先改客户端玩玩
1. 客户端修改
我们先看之前的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 服务端IP:172.40.66.163 # 客户端IP:192.168.40.129 import socket client = socket.socket() # 默认TCP连接 client.connect(('172.40.66.163', 8001)) # 服务端IP,以及服务端开放的端口 # 向服务端发送消息 client.send('我是客户端'.encode()) # 这个 "我是客户端" 是个字符串,我们需要encode一下 data = client.recv(1024) # 接受服务端发来的消息 print(data.decode()) # 打印从服务端发来的消息 client.close() # 关闭
|
这里,连接应该是只有一次,但是我们想要能够一直发送信息,即我们的 send 函数在循环里头。
之后呢,因为是要多次发送,我们不能老是发送一个东西,我们可以加一个 input 来自定义输出内容
除此之外,我们还需要加一个能够关闭请求的过程,即我们输入特定字符时,可以进行关闭会话,加个 if 就行了。
比如我们想要通过输入 “baibai” 来关闭,条件就是
1 2
| if data.decode() == "baibai" break
|
2. 服务器端
原先的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| # 服务端IP:172.40.66.163 # 客户端IP:192.168.40.129 # 服务端 import socket # 创建了一个基于ipv4的,tcp协议的的socket对象 service = socket.socket() # 建立socket TCP连接,实例化为sock service.bind(('172.40.66.163', 8001)) # 绑定本地(服务端)IP,以及对应的端口 ''' 你也可以这样写 client.bind(('0.0.0.0', 8001)) 0.0.0.0表示绑定服务端上所有网卡的IP ''' service.listen(5) # 开启监听模式 # 接收客户端的连接,创建socket连接对象,并且返回客户端的连接地址信息 connection, address = service.accept() # 通过accept来等待客户端的信息 data = connection.recv(1024) # 接收客户端发送的消息,1024指每次接收数据量的大小 # 输出客户端发来的消息 print(data.decode()) # 使用decode是因为通过sock传入的是bytes类型的数据,需要解码才能正确显示 # 向客户端发送消息 connection.send('我是服务端'.encode()) # 这个 "我是服务端" 是个字符串,我们需要encode一下 connection.close()
|
和客户端同理,把send函数套进循环,然后加自定义输入语句
然后就是通信关闭的问题,还是一样加个 if 判断就行
3. 实例代码
服务端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| # 服务端IP:172.40.66.163 # 客户端IP:192.168.40.129 # 服务端 import socket # 创建了一个基于ipv4的,tcp协议的的socket对象 service = socket.socket() # 建立socket TCP连接,实例化为service service.bind(('172.40.66.163', 8001)) # 绑定本地(服务端)IP,以及对应的端口 ''' 你也可以这样写 client.bind(('0.0.0.0', 8001)) 0.0.0.0表示绑定服务端上所有网卡的IP ''' service.listen(5) # 开启监听模式 # 接收客户端的连接,创建socket连接对象,并且返回客户端的连接地址信息 connection, address = service.accept() # 通过accept来等待客户端的信息 # 加死循环,做到能够持续连接 while True: data = connection.recv(1024) # 接收客户端发送的消息,1024指每次接收数据量的大小 if data.decode() == "baibai": break # 输出客户端发来的消息 print(f"来自客户端 {address} 的信息:{data.decode()}") # 使用decode是因为通过sock传入的是bytes类型的数据,需要解码才能正确显示 to_data = input("请输入:") # 自定义输入内容 # 向客户端发送消息 connection.send(to_data.encode()) # 发送 to_data 中的内容,内容是个字符串,我们需要encode一下 connection.close() service.close()
|
客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| # 服务端IP:172.40.66.163 # 客户端IP:192.168.40.129 import socket client = socket.socket() # 默认TCP连接 client.connect(('172.40.66.163', 8001)) # 服务端IP,以及服务端开放的端口 # 加死循环,做到能够持续连接 while True: to_data = input("请输入:") # 自定义输入内容 # 向服务端发送消息 client.send(to_data.encode()) # 发送 to_data 中的内容,内容是个字符串,我们需要encode一下 data = client.recv(1024) # 接受服务端发来的消息 if data.decode() == "baibai": break print(data.decode()) # 打印从服务端发来的消息 client.close()
|
4. 测试
(1) 测试 - 1
客户机发送 baibai

(2) 测试 - 2
服务端发送baibai

5. 问题
可以发现,在整个通信过程中,有很多不同的事件,这些事件需要我们自己处理
比如上面的,断开之后没反应。
如果没有处理的话,容易发生异常
我们问题先放在这里
二. 多客户端连接
1. 代码
当前的服务端仅支持一个服务端对应一个客户端,这里自己试试就行了,我就不演示了。
那么怎么解决这个问题
我们接受客户端的请求是这句话
1 2
| # 接收客户端的连接,创建socket连接对象,并且返回客户端的连接地址信息 connection, address = service.accept() # 通过accept来等待客户端的信息
|
你可能会想,把这玩意放循环里头不就得了嘛。肯定不行哈,不用想都知道,新的会话会覆盖掉旧的会话,得到一个全新的连接对象,之前的那个就死掉了。
而且还会出现话说一半断开的情况,因为在经过 accept() 它就直接阻塞在这里了,没法往下走了,就直接死掉了
不过加循环是必须的,但是我们要处理一下
就改服务端就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| # 服务端IP:172.40.66.163 # 客户端IP:192.168.40.129 # 客户端IP:192.168.40.142 # 服务端 import socket import threading # 创建了一个基于ipv4的,tcp协议的的socket对象 service = socket.socket() # 建立socket TCP连接,实例化为service service.bind(('172.40.66.163', 8001)) # 绑定本地(服务端)IP,以及对应的端口 ''' 你也可以这样写 client.bind(('0.0.0.0', 8001)) 0.0.0.0表示绑定服务端上所有网卡的IP ''' service.listen(5) # 开启监听模式 def handel_socket(con, addr): while True: data = connection.recv(1024) # 接收客户端发送的消息,1024指每次接收数据量的大小 if data.decode() == "baibai": break to_data = input("请输入:") # 自定义输入内容 # 向客户端发送消息 connection.send(to_data.encode()) # 发送 to_data 中的内容,内容是个字符串,我们需要encode一下 print(f"来自客户端 {address} 的信息:{data.decode()}") # 使用decode是因为通过sock传入的是bytes类型的数据,需要解码才能正确显示 # 加死循环,做到能够持续连接 while True: # 接收客户端的连接,创建socket连接对象,并且返回客户端的连接地址信息 connection, address = service.accept() # 通过accept来等待客户端的信息 client_thread = threading.Thread(target=handel_socket, args=(connection, address)) # 输出客户端发来的消息 client_thread.start()
|
2. 实操

能看出来,能够实现通信。但是又出现了一个问题。
我们发现 客户机1 对服务端发起会话的时候,服务端回复时,只是针对 客户端1 进行回复;客户端2 对服务端进行会话的时候,服务端只是对 客户端2 进行回复。
但是在 客户端1 发起请求的时候,我不进行回复。然后 客户端2 发起会话请求,我进行回复,这个时候就出现了BUG,我回复的是 客户端2,那么 客户端1 的会话被搁置了,即服务端现在无法对 客户端1 进行回复了。