TCP 多人聊天室带文件下载 (Linux & Python)

本小案例实现了一个简单的多人聊天室,为实现一对多无干扰传输,采用多线程队列,实现的主要功能有:群聊相关内容、下载服务器端文件。

目录

一、整体功能实现流程图

二、服务器端

基本语法

线程

队列 

三、客户端

四、整合代码

1、服务器端

2、客户端


一、整体功能实现流程图

二、服务器端

基本语法

(需要提前导入类:socket)

服务器端首要任务是创建TCP服务器,其步骤为:

  1. 使用socket创建一个套接字
  2. 使用bind绑定IP和端口

代码实现如下:

# 建立套接字对象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 地址与端口
addr = ('127.0.0.1', 8080)
# 绑定端口
s.bind(addr)
# 涉及监听者个数
s.listen(5)

接下来,我们需要使用accept等待客户端的连接

# 等待接收客户端的连接请求
client, addr = s.accept() 

到了最重要的一步,使用recv/send接收和发送数据

基本使用语法为:

#获取客户端请求的数据
data = conn.recv(1024)				
#向客户端发送数据
conn.sendall(bytes('欢迎你加入我们的大家庭!\n'.encode('utf-8')))	
线程

为实现服务器信息收、发同时进行,此程序使用了线程模块(treadin高级模块)来实现,在开启线程后,独立监听该用户的发来的信息,用于后续处理于转发。 

具体使用方法:

# 导入线程模块
import threading

# 创建监听线程  
# target:线程执行的函数名
# args:以元组的方式给执行任务传参(用户名,数)
r = threading.Thread(target=receive_msg, args=(client, num))

# 开启线程
r.start()
队列 

在接收到用户端的信息后,我们需要将需要群发的信息进行转发,此处使用列表将信息进行非己转发(判断用户名)。

具体使用方法:

import queue

#获取用户端发来的信息
data = client.recv(1024).decode('utf-8')

#创建队列对象
public_message[client] = queue.Queue()

#为队列添加内容
public_message[client].put(data)


#后续获取内容
get_data = public_message[指定的client].get()

三、客户端

相对于服务器端,搭建用户端是较为简单的,创建客户端以后,建立连接成功后,便可以开始愉快的交流啦!

代码实现:

# 创建用户端
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 指定要连接的服务器端口及ip信息
server = ('127.0.0.1', 8080)
# 建立连接
c.connect(server)  

四、整合代码

1、服务器端

server.py

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project :tdp
@File    :server.py
@IDE     :PyCharm 
@Author  :BLUE924
@Date    :2023/6/16 12:26 
"""
import queue
import socket
import threading
import time

num = -1
# 存放已连接的对象
clients = []
# 存放公共消息的容器
public_message = dict()


def file_deal(file_name):
    # 定义函数用于处理用户索要下载的文件
    try:
        # 二进制方式读取
        files = open(file_name, "rb")
        mes = files.read()
    except:
        print("没有该文件")
    else:
        files.close()
        return mes


# 接收消息
def receive_msg(client, num):
    while True:
        time.sleep(1)
        try:
            if client in clients:
                data = client.recv(1024).decode('utf-8')
                # 判断单纯的聊天消息
                if data != '' and data[:4] != 'file':
                    print(data)
                    public_message[client] = queue.Queue()
                    public_message[client].put(data)
                elif data[:4] == 'file':
                    #判断文件传输
                    print("用户需要文件传输")
                    file_name = data[7:]
                    print(data[7:])
                    # 调用函数处理用户下载的文件
                    mes = file_deal(file_name)
                    if mes:
                        # 如果文件不为空发送
                        msg = 'File_content : '.encode() + mes
                        client.send(msg)
                    print("传输完成!")

                else:
                    if client in clients:
                        print("一位用户退出了")
                        clients.remove(client)
                        num = num - 1


        except BaseException as error:

            print('一位用户离开了群聊!')
            if client in clients:
                clients.remove(client)
                num = num - 1


# 转发消息(非/阻塞)
def broadcast():
    while True:
        if len(clients) > 1:
            public_message_clone = [i for i in public_message.keys()]  # 解决字典迭代中操作报错的问题(循环迭代键)
            for client in clients:
                for i in public_message_clone:
                    if i != client and public_message[i].empty() == False:
                        data = public_message[i].get_nowait()  # 注意:相当q.get(False) 非阻塞
                        if data != '':
                            client.send(bytes(data.encode('utf-8')))


def connect():
    # 起群名
    name = str(input("请为此群起群名:"))
    # 建立套接字对象
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 地址与端口
    addr = ('127.0.0.1', 8080)
    # 绑定端口
    s.bind(addr)
    # 涉及监听者个数
    s.listen(5)
    # 建立转发信息的线程
    t = threading.Thread(target=broadcast)
    t.start()
    print("群活跃中....")
    # 目前人数
    global num
    num = 0
    # 存放不同线程的套接字
    while True:
        try:
            client, addr = s.accept()  # 等待接收客户端的连接请求
            if client in clients:
                # 老用户忽略
                pass
            else:
                print('目前群内有:%d 个成员' % int(num + 1))
                client.send(bytes('欢迎你加入我们的大家庭!\n'.encode('utf-8')))
                client.send(bytes(('目前群内有:%d 位志同道合的朋友' % int(num)).encode('utf-8')))
                clients.append(client)
                r = threading.Thread(target=receive_msg, args=(client, num))
                r.start()
                num += 1
        except ConnectionResetError:
            print('Someone left unexcept.')


if __name__ == '__main__':
    connect()

2、客户端

client.py

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project :tdp
@File    :clinet.py
@IDE     :PyCharm 
@Author  :BLUE924
@Date    :2023/6/16 13:08 
"""

import socket
import threading

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server = ('127.0.0.1', 8080)
s.connect(server)  # 建立连接


def receive():
    """
    接收群发信息群
    """
    while True:
        data = s.recv(1024).decode('utf-8')
        if data != '' and data[:15] != 'File_content : ':
            print(data)
        elif data[:15] == 'File_content : ':
            content = data[15:]
            # 创建一个空文件
            new_file = open('下载的文件.txt', "wb")
            # 解码并向文件内写入
            new_file.write(content.encode())
            print("下载成功!")
            new_file.close()

def start():
    # 起名
    name = str(input("请位自己起一个群备注叭~:"))
    t1 = threading.Thread(target=receive, daemon=True)
    t1.start()

    while (True):
        string = input()
        if string == 'exit':
            msg = name + ' : 拜拜我要退出喽,期待下次见面!'
            s.send(bytes(msg.encode('utf-8')))
            s.close()
            break
        elif string == 'file':
            file_name = input("输入文件名:")
            msg = string + ' : ' + file_name
            s.send(bytes(msg.encode('utf-8')))
        else:
            msg = name + ' : ' + string
            s.send(bytes(msg.encode('utf-8')))


if __name__ == '__main__':
    start()
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以使用Python的socket模块来实现一个TCP多人聊天。下面是一个简单的示例代码: ```python import socket import threading def handle_client(client_socket, address): while True: # 接收客户端发送的消息 data = client_socket.recv(1024).decode('utf-8') if not data: # 如果客户端断开连接,则退出循环 break print(f"收到来自{address}的消息:{data}") # 向所有客户端发送消息(广播) for client in clients: client.sendall(data.encode('utf-8')) # 关闭客户端连接 client_socket.close() def start_server(): # 创建套接字 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind(('localhost', 8888)) server_socket.listen(5) print("服务器已启动,等待客户端连接...") while True: # 接受客户端连接请求 client_socket, address = server_socket.accept() print(f"客户端{address}已连接") # 创建新的线程处理客户端连接 client_thread = threading.Thread(target=handle_client, args=(client_socket, address)) client_thread.start() # 存储所有客户端套接字的列表 clients = [] start_server() ``` 这个示例代码使用了`socket`模块来创建服务器和客户端之间的TCP连接。服务器接受客户端连接请求后,为每个客户端创建一个新的线程,用于处理该客户端的消息收发。当有客户端发送消息时,服务器会将该消息广播给所有连接的客户端。 注意:这只是一个简单的示例,没有处理异常情况和安全性等问题。在实际应用中,可能需要进一步完善代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值