通过websocket构建一个基础的聊天服务器

https://objc.com/article/53

websocket server

基于django-private-chat 和 djangorestframework 的websockt 服务端示例

websocket client

前端示例

http://chat.enba.com
需要先登录

username password
user1 password123
user2 password123

WebSocket 的验证方式

支持jwt 和 session 两种方式对websocket进行鉴权

ws_auth_type_jwt_token = "token"
ws_auth_type_session_key = "session_key"
  • 连接的示例url path
ws://127.0.0.1:5002/?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyLCJ1c2VybmFtZSI6IjE4OTAxMTA4NzE5IiwiZXhwIjoxNTY2Mjc2OTc2LCJlbWFpbCI6IiIsIm1vYmlsZSI6IjE4OTAxMTA4NzE5In0.IzgSstfFrDB2ehf778HHx-2Hrw6YDE54_sexFAhC9Z0&opponent=xiaoyuan
  • 建立连接
let base_ws_server_path = 'wss://chat.enba.com'
let opponent_username = 'xiaoyuan'
websocket = new WebSocket(base_ws_server_path + '?session_key={{ request.session.session_key }}' + '&opponent={{ opponent_username }}');

初始化项目

  • python3.6

  • 创建python虚拟环境

mkvirtualenv -p /usr/bin/python3 websocketserver
source ~/.virtualenvs/websocketserver/bin/activate
  • 安装依赖
pip install -r requirements.txt
  • 在WebSocketServer目录下创建private_config.py,此文件用于存储云片apikey, 添加YUNPIAN_APIKEY = ''
cd websocket_server
vim WebSocketServer/private_config.py
  • 生成数据库
# 1. 创建更改的文件
python manage.py makemigrations
# 2. 将生成的py文件应用到数据库
python manage.py migrate
  • 创建管理员
python manage.py createsuperuser

运行前端示例

  • 请先配置客户端请求的host和port
CHAT_WS_CLIENT_HOST = '127.0.0.1'
CHAT_WS_CLIENT_PORT = 80
CHAT_WS_CLIENT_ROUTE = 'ws/'
  • 运行
python manage.py runserver 8000
  • 非DEBUG时,需要收集静态文件
python manage.py collectstatic --noinput

运行websocket服务端

  • 请先配置websocket监听的host和port
CHAT_WS_SERVER_PROTOCOL = 'ws'
CHAT_WS_SERVER_HOST = '127.0.0.1'
CHAT_WS_SERVER_PORT = 5002
  • 运行run_chat_server启动websocket 服务
python manage.py run_chat_server

或者

  • 通过systemd服务的配置run_chat_server
    将项目中bin/chatserver.service拷贝到/lib/systemd/system目录下(注意:修改.service中的项目路径)。
cp bin/chatserver.service /lib/systemd/system

启动websocket 服务

sudo systemctl start chatserver.service

如果时修改或新建的服务文件需要先执行systemctl daemon-reload ,告诉systemd系统,然后再启动chatserver.service,不然无法正常启动。

问题

  • 问题1: 本地测试环境下websocket正常工作,但是本地服务器使用nginx反向代理未正常在线,显示WebSocket is already in CLOSING or CLOSED state.

解决:
此问题是由webSocket在nginx的proxy_pass配置错误导致的,proxy_pass http://websocket_server;修改为proxy_pass http://websocket_server/;问题解决。

  • 问题2: 生产环境部署到阿里云ECS时,使用nginx做websocket的反向代理后,客户端请求总是502。
    同样的配置,在本地服务器通过nginx没有,但是阿里云ECS部署就会导致502错误。
    Error:enba:186 WebSocket connection to 'ws://chat.enba.com/ws/9ygfrczj6le3buh28b393cv20w5hzj4l/enba' failed: Error during WebSocket handshake: Unexpected response code: 502

解决:
由于websocket服务使用python manage.py run_chat_server命令开启的,并且绑定的hostlocalhost、port为5002,通过netstat -atnp命令在本地服务器查询到5002网络端口已开启,而在阿里云ECS服务端未查询到此网络端口,期间很是郁闷,不过此时我已经找到了问题所在。此问题是由于nginx配置错误导致,在nginx的proxy_pass为127.0.0.1:5002,而websockets监听的为localhost:5002,导致反向代理失败。通过修改初始化websockets.serve()方法的host参数将localhost修改为127.0.0.1问题解决,重启chatserver.service问题解决。

  • 问题3: ws协议跨域问题
    由于HTTPS是基于SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密,所以在HTTPS站点调用某些非SSL验证的资源时浏览器可能会阻止。比如原本https的前端项目中使用了类似ws://chat.enba.com/ws/9ygfrczj6le3buh28b393cv20w5hzj4l/enba的websockt协议,会出现类似如下错误:
Mixed Content: The page at 'https://chat.enba.com/dialogs/enba' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://chat.enba.com/ws/9ygfrczj6le3buh28b393cv20w5hzj4l/enba'. This request has been blocked; this endpoint must be available over WSS.

解决方法:

  • 通过wss协议实际是websocket+SSL,就是在websocket协议上加入SSL层,类似https(http+SSL)。

  • 利用nginx代理wss

    • 客户端发起wss连接连到nginx
    • nginx将wss协议的数据转换成ws协议数据并转发到websocket协议端口
    • websocket收到数据后做业务逻辑处理
    • websocket给客户端发送消息时,则是相反的过程,数据经过nginx/转换成wss协议然后发给客户端
  • nginx配置ssl和wss
    由于我在nginx配置中已配置ssl证书,所以只需要在server 443端口处,添加以下:

   # 此路由为websocket服务
   location /ws/ { # CHAT_WS_CLIENT_ROUTE
       # 后面必须要带`/`
       proxy_pass http://websocket_server/;
       proxy_http_version 1.1;
       proxy_connect_timeout 10s;                #配置点1
       proxy_read_timeout 60s;                  #配置点2,如果没效,可以考虑这>个时间配置长一点
       proxy_send_timeout 12s;                  #配置点3
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection "Upgrade";
   }
  • websocket服务端和前端进行websocket通讯时使用wss协议头即可。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容