用socket实现一个即时通讯程序 要求实现私聊 群聊 发送文件功能
时间: 2023-07-14 18:14:11 浏览: 72
以下是一个基于Python的简单即时通讯程序,包括私聊、群聊和发送文件功能。其中,使用了socket和select模块。
服务端代码:
```python
import socket
import select
import os
# 创建TCP套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置地址复用
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定地址和端口
server_socket.bind(('localhost', 8000))
# 监听客户端连接
server_socket.listen(5)
# 存储客户端套接字对象和昵称的字典
clients = {}
print('Server is running...')
while True:
# 监听套接字和客户端套接字列表
sockets_list = [server_socket] + list(clients.keys())
# 使用select模块监听套接字
read_sockets, _, _ = select.select(sockets_list, [], [])
for sock in read_sockets:
# 如果是服务器套接字,表示有新的客户端连接
if sock == server_socket:
client_socket, client_address = server_socket.accept()
# 发送欢迎消息
client_socket.send(b'Welcome to the chatroom! Please enter your nickname: ')
# 如果是客户端套接字,表示有消息发送过来
else:
# 接收消息
try:
message = sock.recv(1024)
# 如果客户端断开连接
if not message:
# 关闭套接字并从字典中删除
sock.close()
del clients[sock]
continue
# 如果客户端还没有设置昵称
if sock not in clients:
nickname = message.decode('utf-8').strip()
# 如果昵称已经存在
if nickname in clients.values():
sock.send(b'This nickname is already taken. Please enter another one: ')
continue
clients[sock] = nickname
# 发送欢迎消息
message = f'{nickname} has joined the chatroom!\n'.encode('utf-8')
else:
message = message.decode('utf-8')
# 判断是否是私聊
if message.startswith('@'):
dest_nickname, message = message.split(' ', 1)
dest_sock = None
# 查找目标客户端套接字
for sock, nickname in clients.items():
if nickname == dest_nickname[1:]:
dest_sock = sock
break
# 如果目标客户端不存在
if not dest_sock:
sock.send(f'{dest_nickname[1:]} is not online.\n'.encode('utf-8'))
continue
# 发送私聊消息
message = f'{clients[sock]} (private): {message}'
message = message.encode('utf-8')
dest_sock.send(message)
continue
# 判断是否是发送文件
if message.startswith('#'):
dest_nickname, filename = message.split(' ', 1)
dest_sock = None
# 查找目标客户端套接字
for sock, nickname in clients.items():
if nickname == dest_nickname[1:]:
dest_sock = sock
break
# 如果目标客户端不存在
if not dest_sock:
sock.send(f'{dest_nickname[1:]} is not online.\n'.encode('utf-8'))
continue
# 发送文件
try:
with open(filename.strip(), 'rb') as f:
data = f.read()
message = f'{clients[sock]} (file): {filename}'
message = message.encode('utf-8')
dest_sock.send(message)
dest_sock.send(data)
except:
sock.send(f'Failed to send file "{filename.strip()}".\n'.encode('utf-8'))
continue
# 发送群聊消息
message = f'{clients[sock]}: {message}'
message = message.encode('utf-8')
for client_sock in clients.keys():
if client_sock != sock:
client_sock.send(message)
# 如果出现异常,关闭套接字并从字典中删除
except:
sock.close()
del clients[sock]
# 关闭服务器套接字
server_socket.close()
```
客户端代码:
```python
import socket
import threading
import os
# 创建TCP套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
client_socket.connect(('localhost', 8000))
# 接收欢迎消息并设置昵称
nickname = input(client_socket.recv(1024).decode('utf-8'))
client_socket.send(nickname.encode('utf-8'))
# 接收消息的函数
def receive():
while True:
try:
message = client_socket.recv(1024).decode('utf-8')
print(message)
except:
print('An error occurred!')
client_socket.close()
break
# 发送消息的函数
def send():
while True:
message = input()
# 判断是否是退出命令
if message == '/quit':
client_socket.close()
break
# 判断是否是私聊
if message.startswith('@'):
dest_nickname, message = message.split(' ', 1)
message = message.encode('utf-8')
message = '@' + dest_nickname[1:] + ' ' + message
client_socket.send(message)
continue
# 判断是否是发送文件
if message.startswith('#'):
filename = message.split(' ', 1)[1].strip()
# 判断文件是否存在
if not os.path.exists(filename):
print(f'The file "{filename}" does not exist!')
continue
message = '#' + nickname + ' ' + filename
message = message.encode('utf-8')
client_socket.send(message)
try:
with open(filename, 'rb') as f:
data = f.read()
client_socket.send(data)
print(f'The file "{filename}" has been sent successfully!')
except:
print(f'Failed to send file "{filename}".')
continue
# 发送群聊消息
message = message.encode('utf-8')
client_socket.send(message)
# 启动接收消息的线程和发送消息的线程
receive_thread = threading.Thread(target=receive)
send_thread = threading.Thread(target=send)
receive_thread.start()
send_thread.start()
```
使用方法:
1. 分别运行服务端代码和客户端代码。
2. 客户端会提示输入昵称,输入后回车即可。
3. 客户端可以输入消息发送给所有客户端,也可以使用@昵称指定私聊某个客户端。
4. 客户端可以使用#文件名发送文件给其他客户端。客户端发送文件时,服务端会先发送一条消息,包括发送者的昵称和文件名,然后再发送文件内容。接收到文件的客户端会自动保存文件到当前目录下。
5. 客户端可以使用/quit命令退出程序。