基于python实现的聊天室(服务端)

基于python实现的聊天室(服务端),第1张

前言

就是自己想用python做一个聊天室,然后看看socket库,websocket库,有点底层,然后也会用到协程的东西,不是很明白,一时间也不知道怎么写,然后就用了封装好的python-socketio来实现,做好了以后,跟同学用,被吐槽说滚轮不会自动下滑到底部,难用,于是我找天找地,在网上啥也没找到,经过自己一个多小时的摸索,终于找到了解决方法
想看看聊天室的可以到https://github.com/cgynb/a-flask-project/tree/guiChatroom看看,客户端的gui我有打包,但是服务端的server.py因为有了eventlet,打包的时候坑太多了,就放弃了
如果想跑来看看的话,要先运行服务端的server.py,然后会给服务端ip,客户端需要填入ip才能加入群聊,当然这个程序也不是一定要这么麻烦的,服务端程序在公网跑就可以有固定的ip了,客户端将ip固定下来即可

需求

需要用python-socketio实现双向通信
由于对协程不是很熟悉,不大会使用,所以我就先放弃使用asyncio,具体使用官方文档写的还是相当详细的,我这里就只说说这个聊天室通信的实现吧

具体内容 导入模块

socketio就是通信使用的模块了;
eventlet.wsgi是一个网络库,可以看看这篇文章,这里就不赘述了,因为我目前也没有能力搞得很明白;
random是一个随机数模块,因为是匿名聊天室,所以使用random产生随机整数从昵称文件里选取一个;
socket模块在这里是用来产生主机ip的,因为在运行的时候eventlet.wsgi.server(eventlet.listen((‘0.0.0.0’, 5000)), app),我是没想到,我这样写,它真就。






(20380) wsgi starting up on http://0.0.0.0:5000,这样的,至于为什么把ip写成’0.0.0.0’,可以看看这篇文章;
logging是处理日志的模块,我这里并没有什么高级应用,只是为了打印一下上面用socket模块给到的主机ip罢了。






import socketio
import eventlet.wsgi
import random
import socket
import logging
打印主机ip
hostname = socket.gethostname()
ip = socket.gethostbyname(hostname)

logging.basicConfig()
logging.warning('        服务器ip:     ' + ip)

这样他就会打印出主机ip了,socket和logging库的使用就到此为止了

得到随机昵称

通过这里可以看到name_list是储存当前房间里的人的昵称的,可以看到name_list中元素是以(name, sid)的形式存储起来的,sid是客户端连接服务端的时候服务端分配给的唯一id,那么这里为什么要把sid和name绑定在一起呢,在后面会有讲到,这里是为了统计房间在线用户。


random库的使用也到此为止了

name_list = []
def create_username(sid):
    with open('name.txt', 'r', encoding='utf-8') as f:
        names = f.readlines()
        names = list(map(lambda x: x.strip(), names))
        name = names[random.randint(0, len(names)-1)]
        while name in name_list:
            name = names[random.randint(0, len(names) - 1)]
        name_list.append((name, sid))
    return name
服务器跑起来

可以看到,我甚至连官方文档的注释都没有删,因为真的是复制过来就能用。






那翻译一下第一行代码就是创建一个socket.io服务器,第二行是把他包装秤WSGI应用,那么WSGI又是什么呢,可以看看这篇文章
socket.io是一个事件驱动的库,可以看到最底下有个一装饰器@sio.on(‘msg’),如果有一点js基础的话可以知道这是一个事件监听函数,就是触发了这个事件,就会触发执行函数,具体来看,就是触发了msg事件,函数内部的sio.emit()函数就会携带data向连接服务端的用户(没有使用房间,否则可以发送到指定房间)发送’msg’事件。



那么上面的两个connect还有disconnect函数呢,为什么没有用@sio.on(‘connect’)和@sio.on(‘disconnect’)呢?诶,这里就要看看官方文档了

The connect, connect_error and disconnect events have to be defined explicitly and are not invoked on a catch-all event handler.

chrome自带的翻译一下

和事件必须明确定义connect,connect_error并且disconnect不能在包罗万象的事件处理程序上调用。


所以,只能使用@sio.event这个装饰器,当发生了connect/disconnect事件时,会执行connect和disconnect函数,那我们具体看看这两个函数
connect函数中,我们可以看到data这个字典中的username是使用上面讲的create_username生成的,action表示这个客户端 *** 作,是登陆,而name_list在客户端那里就可以改变用户列表,增加新用户。


发送data
disconnect函数中,得到断开用户的sid,删除name_list中该用户信息,然后发送data到客户端,即可改变用户列表,删除退出用户

# create a Socket.IO server
sio = socketio.Server()

# wrap with a WSGI application
app = socketio.WSGIApp(sio)


@sio.event
def connect(sid, environ, auth):
    data = {'username': create_username(sid), 'action': 'login', 'name_list': name_list}
    sio.emit('msg', data)
    print('connect ', sid)


@sio.event
def disconnect(sid):
    for i, j in name_list:
        if j == sid:
            name_list.remove((i, j))
    sio.emit('msg', {'action': 'logout', 'name_list': name_list})
    print(name_list)
    print('disconnect ', sid)


@sio.on('msg')
def msg(sid, data):
    print(data)
    sio.emit('msg', data)


if __name__ == '__main__':
    eventlet.wsgi.server(eventlet.listen(('', 5000)), app)

不知道各位有没有发现,登录,退出,发送消息,用的都是’msg’事件,这样不会乱掉吗,其实是不会滴,因为可以看到,不同动作,我设置的action不同,这样客户端就可以辨识应该做什么(做几次判断action即可)。


总结

通信的内容就这么多了,内容不多,如有问题,请多多指教

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/571158.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存