基于多线程与多进程的简易聊天室

功能实现

服务端

  • 当有新的客户端连接时,显示连接信息
  • 当有客户端发送消息时,显示消息发送者和内容

客户端

  • 客户端连接时,显示本客户端的连接信息
  • 客户端连接时,已连接的客户端收到新客户端的连接信息
  • 当某一客户端发送消息时,所有客户端收到发送者和内容

运行预览

思路

服务端

1.设cpu核数为n,首先开n个进程

2.每个进程开2n个线程

3.使用进程安全队列和字典,前者存放发送的消息,后者保存连接的客户端

4.写send_data方法,用于向每个客户端发送数据

5.写worker_process方法,进程调用这个方法用于开线程并接收客户端连接,并调用send_data方法

6.开线程调用worker_thread方法用于客户端接收数据

客户端

1.recv_data方法,接收并显示服务端发送的数据

2.while True可以不断发送信息

完整代码

服务端

from multiprocessing import Pool, cpu_count,Manager
from multiprocessing.pool import ThreadPool
import socket


#从队列中拿出数据,发给所有连接上的客户端
def send_data(dict_proxy, queue_proxy):
    while True:
        data = queue_proxy.get()        #从队列中拿出消息,发送给所有连接上来的客户端
        print(data.decode())
        for conn in dict_proxy.values():
            conn.send(data)



def worker_thread(connection, addr, dict_proxy, queue_proxy):
    while True:
        try:
            recv_data = connection.recv(1024)
            if recv_data:
                data = "来自{addr} 的消息:{data}".format(addr=addr, data=recv_data.decode())
                queue_proxy.put(data.encode())     #把消息添加到到队列中
            else:
                raise Exception
        except:
            dict_proxy.pop(addr)                #从字典中删掉退出的客户端
            data = '用户{}退出'.format(addr)
            queue_proxy.put(data.encode())      #把退出消息添加到队列中
            connection.close()
            break



def worker_process(server, dict_proxy, queue_proxy):
    thread_pool = ThreadPool( cpu_count()*2 )   #分配2倍CPU个数的线程
    thread_pool.apply_async(send_data, args=(dict_proxy, queue_proxy))
    #发送数据
    while True:
        conncetion, remote_address = server.accept()        #接收客户端连接,生成对等套接字

        dict_proxy[remote_address] = conncetion   #把套接字加入字典中

        data = '用户{}登录'.format(remote_address)
        queue_proxy.put(data.encode())            #将用户登录消息添加到队列中
        thread_pool.apply_async(worker_thread, args=(conncetion, remote_address, dict_proxy, queue_proxy))
        #接收数据

if __name__ == '__main__':

    server = socket.socket()
    server.bind(('127.0.0.1', 8088))
    server.listen(1000) #最多供1000客户端连接

    mgr = Manager()
    dict_proxy = mgr.dict()         #进程安全字典,用来保存连接上来的客户端,
    queue_proxy = mgr.Queue()       #进程安全队列,把客户端发过来的消息通过队列传递

    n = cpu_count()                 #cpu核数
    process_pool = Pool(n)
    for i in range(n):              #充分利用CPU,为每一个CPU分配一个进程
        process_pool.apply_async(worker_process, args=(server, dict_proxy, queue_proxy))
             #把server服务端放到进程里面

    process_pool.close() #停止提交数据
    process_pool.join() #阻塞,等待子进程运行完毕才继续运行主进程

客户端


import socket
import threading


def recv_data():  #接收并显示服务端发送的信息
    while True:
        data = client.recv(1024)
        print(data.decode())



client = socket.socket()
client.connect(('127.0.0.1', 8088))

thread = threading.Thread(target=recv_data, daemon=True)
thread.start()

while True:
    a = input('')
    client.send(a.encode())

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值