帮助文档
专业提供香港服务器、香港云服务器、香港高防服务器租用、香港云主机、台湾服务器、美国服务器、美国云服务器vps租用、韩国高防服务器租用、新加坡服务器、日本服务器租用 一站式全球网络解决方案提供商!专业运营维护IDC数据中心,提供高质量的服务器托管,服务器机房租用,服务器机柜租用,IDC机房机柜租用等服务,稳定、安全、高性能的云端计算服务,实时满足您的多样性业务需求。 香港大带宽稳定可靠,高级工程师提供基于服务器硬件、操作系统、网络、应用环境、安全的免费技术支持。
服务器资讯 / 香港服务器租用 / 香港VPS租用 / 香港云服务器 / 美国服务器租用 / 台湾服务器租用 / 日本服务器租用 / 官方公告 / 帮助文档
python套接字(二):实现一个服务器和多客户端连接
发布时间:2024-03-06 21:13:10   分类:帮助文档
python套接字(二):实现一个服务器和多客户端连接






文章目录
前言一、问题二、实现一个服务器连接多个客户端1、问题分析2、代码实现a、服务器端b、客户端
3、运行




前言
在上一篇博客python套接字(一):socket的使用简单说明了一下套接字的使用,也实现了使用套接字来传输消息,但是也有一个问题,就是这种实现方式只能一个服务器连接一个客户端,意味着有几个个客户就要创建结果服务器,而且客户端直接还不能通信,这样就和现实生活中的情况不符,接下来讲一下如何实现一个服务器和多个客户端进行连接。本篇博客参考了python+tcp实现多人聊天室。
一、问题
在上一章的基础上在执行客户端代码,相当于有两个客户端同时向服务器发送请求,会有如下结果: 客户端: 服务器: 你会发现,服务器上面既没有打印第二个客户端的信息,也没有显示第二个客户端发送的消息,说明服务器只能处理第一个客户端的消息。
二、实现一个服务器连接多个客户端
1、问题分析
为什么两个客户端都能连接服务器,但是服务器只能处理一个客户端的消息呢?因为服务器里面只有一个主线程,该线程接收到第一个客户端的连接之后,就腾不出手来解决其他线程了。要解决这个问题,就要使用到多线程。
2、代码实现
目标:模拟创建一个多人聊天室(类似微信群),一个人在上面发消息,所有客户端都能看到。 因为有些命令有特殊的功能,因此自定义了如下规则:
命令格式说明name -n更改用户名为name并且重新进入聊天室message -ta发送消息给聊天室的所有成员exit退出聊天室
a、服务器端
服务器端不仅要接收源源不断的客户端请求,而且还要接收和发送数据,所以大概的设计思路如下:主线程负责对发起请求的客户创建链接,并且将每个用户对应的链接保存到一个字典中去,方便调用。对于每个用户链接,都创建两个子线程,一个子线程用来发送数据,另外一个子线程用来接收数据。实现代码如下: tcp_server.py
import socket
from threading import Thread
import time
import sys


# 创建存储对象
class Node:
def __init__(self):
self.Name = None # 用户名
self.Thr = None # 套接字连接对象


class TcpServer:
user_name = {} # 存储用户信息; dict 用户名:Node对象

def __init__(self, port):
"""
初始化服务器对象
port: 服务器端口
"""
self.server_port = port # 服务器端口
self.tcp_socket = socket.socket() # tcp套接字
self.tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 端口重用
self.tcp_socket.bind(self.server_port)

def start(self):
"""
启动服务器
"""
self.tcp_socket.listen(10) # 设置服务器接受的链接数量
print(self.get_time(), "系统:等待连接")
while True:
try:
conn, addr = self.tcp_socket.accept() # 监听客户端的地址和发送的消息
except KeyboardInterrupt: # 按下ctrl+c会触发此异常
self.tcp_socket.close() # 关闭套接字
sys.exit("\n" + self.get_time() + "系统:服务器安全退出!") # 程序直接退出,不捕捉异常
except Exception as e:
print(e)
continue

# 为当前链接创建线程
t = Thread(target=self.do_request, args=(conn, ))
t.start()

def do_request(self, conn):
"""
监听客户端传送的消息,并将该消息发送给所有用户
"""
conn_node = Node()
while True:
recv_data = conn.recv(1024).decode('utf-8').strip() # 获取客户端发来的数据
info_list = recv_data.split(" ") # 切割命令

# 如果接收到命令为exit,则表示该用户退出,删除对应用户信息,关闭连接
if recv_data == "exit":
msg = self.get_time() + " 系统:用户" + conn_node.Name + "退出聊天室!"
print(msg)
self.send_to_other(conn_node.Name, msg)
conn.send('exit'.encode("utf-8"))
self.user_name.pop(conn_node.Name)
conn.close()
break
else:
try:
A = info_list[-2], info_list[-1]
except IndexError:
conn.send((self.get_time() + ' 系统:无法识别您的指令,请重新输入!').encode('gb2312'))
continue

if info_list[-1] == '-n':
# 新用户注册
print(self.get_time() + ' 系统:' + info_list[0] + '连接成功')
data_info = self.get_time() + ' 系统:' + info_list[0] + '加入了聊天'
self.send_to_all(data_info)
conn.send('OK'.encode('utf-8'))
conn_node.Name = info_list[0]
conn_node.Thr = conn
self.user_name[info_list[0]] = conn_node
elif info_list[-1] == '-ta':
# 群发消息
msg = self.get_time() + ' %s:' % conn_node.Name + ' '.join(info_list[:-1])
self.send_to_all(msg)

def send_to_all(self, msg):
"""
对所有用户发送消息
"""
print(msg)
for i in self.user_name.values():
i.Thr.send(msg.encode('utf-8'))

def send_to_other(self, name, msg):
"""
对除了当前发送信息的用户外的其他用户发送消息
"""
# print("收到消息:" + msg)
for n in self.user_name:
if n != name:
self.user_name[n].Thr.send(msg.encode('utf-8'))
else:
continue

def get_time(self):
"""
返回当前系统时间
"""
return '[' + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ']'


if __name__ == '__main__':
HOST = "127.0.0.1"
POST = 9999
server = TcpServer((HOST, POST))
server.start()


b、客户端
客户端就简单一点,只需要不断的发送数据和接收数据即可。主线程创建链接并和服务器连接。然后创建两个子线程,分别负责数据的接收和发送。代码实现如下: tcp_clinet.py
import socket
from threading import Thread


class TcpClient:
server_addr = ('127.0.0.1', 9999)

def __init__(self):
self.tcp_cli_socket = socket.socket()

def msg_recv(self):
"""
接收数据
"""
while True:
data = self.tcp_cli_socket.recv(1024)
if data.decode("utf-8") == "exit":
print('客户端退出')
self.tcp_cli_socket.close()
break

print(data.decode("utf-8"))

def msg_send(self):
"""
发送数据
"""
while True:
data_info = input("请发言:")
if data_info == "exit":
self.tcp_cli_socket.send(data_info.encode("utf-8"))
break
else:
self.tcp_cli_socket.send((data_info + ' -ta').encode("utf-8"))

def start(self):
"""
连接服务器
"""
try:
self.tcp_cli_socket.connect(self.server_addr)
except Exception as e:
print("连接失败,请重试!")
self.tcp_cli_socket.close()
print(e)
return

while True:
name = input("请输入用户名:")
self.tcp_cli_socket.send((name + ' -n').encode('utf-8'))
data = self.tcp_cli_socket.recv(128).decode('utf-8')
print(data)
if data == "OK":
print("你已成功进入聊天室")
break
else:
print(data)

t = Thread(target=self.msg_recv)
t.start()
t1 = Thread(target=self.msg_send)
t1.start()


if __name__ == '__main__':
client = TcpClient()
client.start()

3、运行
启动一个服务器和两个客户端,两个客户端之间进行交流,服务器则负责转发它们发送的消息(有点瑕疵) 可以看到它们发送的消息对方都能收到。 下一章:python套接字(三):结合pyside2实现多人聊天室




香港云服务器租用推荐
服务器租用资讯
·广东云服务有限公司怎么样
·广东云服务器怎么样
·广东锐讯网络有限公司怎么样
·广东佛山的蜗牛怎么那么大
·广东单位电话主机号怎么填写
·管家婆 花生壳怎么用
·官网域名过期要怎么办
·官网邮箱一般怎么命名
·官网网站被篡改怎么办
服务器租用推荐
·美国服务器租用
·台湾服务器租用
·香港云服务器租用
·香港裸金属服务器
·香港高防服务器租用
·香港服务器租用特价