逍遥友 2020-04-07
import socket
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind((‘0.0.0.0‘,8002))
server.listen()
print(‘server 已经启动,欢迎连接‘)
sock,addr = server.accept()
while True: #使用循环实现服务器端永久等待消息
data=socl.recv(1024)
print(data.decode())
if data.decode()==‘exit‘: #如果客户端发来exit,就断开连接,判断语句要放在接收到客户端消息后,立刻执行,否则,不起作用。
break
send_to_client=input() #输入发送给客户端的消息
sock.send(send_to_client.encode())
server.close() #关闭客户端连接
sock.close() #关闭sock连接
#上述代码为服务器端代码
#以下代码是客户端代码
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect((‘127.0.0.1‘,8002))
while True:
send_to_server = input()
client.send(send_to_server.encode())
data = client.recv(1024)
print(data.decode())
if data.decode()==‘exit‘:
break
client.close()以上代码只能实现一个客户端和服务器通信。要实现多个客户端和服务器通信,就需要使用线程。把每个客户端和服务器的连接都当做是一个线程,这样,线程之间互不干扰,顺利运行。
import socket
import threading
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind((‘0.0.0.0‘,8002))
server.listen()
print(‘server 已经启动,欢迎连接‘)
def handle_client(sock): #定义函数,线程执行体
while True: #每一个线程和服务器的通信都是多次
data = sock.recv(1024)
print(data.decode())
send_to_client = input()
sock.send(send_to_client.encode())
while True: #服务器不知道客户端连接的数量,所以依然使用循环
sock,addr=server.accept() #服务器连接到了一个客户端
threading.Thread(target=handle_client,args=(sock,)).start() #启动一个线程执行和客户端的交互在使用线程实现了多个客户端和服务器之间的通信后。
要实现群聊的功能,就把服务器当做一个转发机构,专门转发各种客户端发来的信息。
由于在客户端中input方法输入发送数据,而该方法是一个阻塞方法,必须先输入再发送。所以也可把客户端的接收,发送看做是一种线程,发送接收互不干扰。
在群聊中,设置客户端标识,方便所有客户端明确信息从哪里发出。
关闭某个客户端后,服务器不会报错,需要异常处理机制。
import socket
import threading
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind((‘0.0.0.0‘,8004))
server.listen()
print(‘server 已经启动,欢迎连接‘)
client_sockets = []
def handle_client(sock): #服务器转发数据,定义客户端标识,处理客户端退出异常
try: #处理某个客户端退出的异常
username=sock.recv(1024).decode() #接收客户端标识
for client in client_sockets: #发送消息说明每个客户端加入群聊
client.send((‘欢迎【‘+username+‘】加入群聊‘).encode())
while True: #接收客户端标识后,开始接收客户端消息
data=sock.recv(1024).decode() #接收客户端标识
if len(client_sockets)>0: #客户端列表中国如果有客户,向每个客户端发送消息
for client in client_sockets:
client.send((username+‘说:‘+data).encode())
except Exception as e:
client_socket.remove(sock) #出现客户端退出群聊,服务器出现异常,删掉该连接
for client in clietn_sockets: #向每个客户端发送某客户端退出群聊
client.send((username+‘已退出群聊‘).encode())
while True: #循环出现多个客户端连接
sock,addr= server.accept()
client_sockets.append(sock)
sock.send(‘欢迎加入群聊,请输入您的昵称:‘.encode())
threading.Thread(target=handle_client,args=(sock,)).start() #启动服务器连接客户端
#上述是实现群聊的完全代码
#以下是客户端代码
import socket
import threading
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect((‘127.0.0.1‘,8004))
def receive(client):
while True:
print(client.recv(1024).decode())
def sendto(client):
while True:
send_to_other_client = input()
client.send(send_to_other_client.encode())
threading.Thread(target=receive,args=(client,)).start()
threading.Thread(target=sendto,args=(client,)).start()在群聊的基础上,实现私聊。需要使用字典数据类型存储每个客户端的连接和输入的昵称名。
客户端的代码不需要做出改变。
import socket
import threading
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind((‘0.0.0.0‘,8004))
server.listen()
print(‘server 已经启动,欢迎连接‘)
client_sockets = {} #使用字典数据类型,存放连接和输入昵称之间的映射
def handle_client(sock): #处理私聊
try: #处理私聊,某客户端退出群聊异常不能缺失
username=sock.recv(1024).decode() #获取输入昵称
client_sockets[sock]=username #连接和输入昵称相互匹配
for client in client_sockets.keys():
client.send((‘欢迎【‘+username+‘】加入群聊‘).encode())
while True: #客户端输入循环
data=sock.recv(1024).decode() #服务器接受了客户端昵称后,再接受信息
send_data = ‘【‘+username+‘】说:‘+data
if data.startswith(‘@‘): #处理私聊,私聊以@开头
msg=data.split(‘ ‘) #分割输入信息,
private_name=msg[0][1:] #获取输入昵称
for k,v in client_sockets.items(): #遍历映射,查找符合的昵称
if v==private_name: #找到符合的用户昵称
k.send(send_data.encode()) #向该昵称的连接发生私聊信息
else: #不是私聊,就是普通群聊
if len(client_sockets)>0:
for client in client_sockets.keys(): #依次遍历各个连接
client.send(send_data.encode())
exception Exception as e:
client_sockets.pop(sock) #出现异常,删除连接
for client in client_sockets.keys():
client.send((username+‘已退出群聊‘).encode())
while True: #客户端连接未知
sock,addr=server.accept()
client_sockets[sock]=‘‘
sock.send(‘欢迎您加入群聊,请输入您的昵称:‘.encode())
threading.Thread(target=handle_client,args=(sock,)).start() #启动服务器,连接客户端