python实现一对一聊天_vue+django实现一对一聊天功能

vue+django实现一对一聊天和消息推送的功能。主要是通过websocket,由于Django不支持websocket,所以我使用了django-channels。考虑到存储量的问题,我并没有把聊天信息存入数据库,服务端的作用相当于一个中转站。我只讲述实现功能的结构性代码,具体的实现还请大家看源代码。

效果展示

实现过程

后端

首先,我们需要先定义websocket的两条连接路径。ws/chat/xxx/(xxx指代聊天组)这条路径是当聊天双方都进入同一个聊天组以后,开始聊天的路径。push/xxx/(xxx指代用户名)这条是指当有一方不在聊天组,另一方的消息将通过这条路径推送给对方。ws/chat/xxx/只有双方都进入聊天组以后才开启,而push/xxx/是自用户登录以后,直至退出都开启的。

websocket_urlpatterns = [

url(r'^ws/chat/(?P[^/]+)/$', consumers.ChatConsumer),

url(r'^push/(?P[0-9a-z]+)/$', consumers.PushConsumer),

]

我们采用user_a的id加上下划线_加上user_b的id的方式来命名聊天组名。其中id值从小到大放置,例如:195752_748418。当用户通过ws/chat/group_name/的方式向服务端请求连接时,后端会把这个聊天组的信息放入一个字典里。当连接关闭时,就把聊天组从字典里移除。

class ChatConsumer(AsyncJsonWebsocketConsumer):

chats = dict()

async def connect(self):

self.group_name = self.scope['url_route']['kwargs']['group_name']

await self.channel_layer.group_add(self.group_name, self.channel_name)

# 将用户添加至聊天组信息chats中

try:

ChatConsumer.chats[self.group_name].add(self)

except:

ChatConsumer.chats[self.group_name] = set([self])

#print(ChatConsumer.chats)

# 创建连接时调用

await self.accept()

async def disconnect(self, close_code):

# 连接关闭时调用

# 将关闭的连接从群组中移除

await self.channel_layer.group_discard(self.group_name, self.channel_name)

# 将该客户端移除聊天组连接信息

ChatConsumer.chats[self.group_name].remove(self)

await self.close()

接着,我们需要判断连接这个聊天组的用户个数。当有两个用户连接这个聊天组时,我们就直接向这个聊天组发送信息。当只有一个用户连接这个聊天组时,我们就通过push/xxx/把信息发给接收方。

async def receive_json(self, message, **kwargs):

# 收到信息时调用

to_user = message.get('to_user')

# 信息发送

length = len(ChatConsumer.chats[self.group_name])

if length == 2:

await self.channel_layer.group_send(

self.group_name,

{

"type": "chat.message",

"message": message.get('message'),

},

)

else:

await self.channel_layer.group_send(

to_user,

{

"type": "push.message",

"event": {'message': message.get('message'), 'group': self.group_name}

},

)

async def chat_message(self, event):

# Handles the "chat.message" event when it's sent to us.

await self.send_json({

"message": event["message"],

})

# 推送consumer

class PushConsumer(AsyncWebsocketConsumer):

async def connect(self):

self.group_name = self.scope['url_route']['kwargs']['username']

await self.channel_layer.group_add(

self.group_name,

self.channel_name

)

await self.accept()

async def disconnect(self, close_code):

await self.channel_layer.group_discard(

self.group_name,

self.channel_name

)

# print(PushConsumer.chats)

async def push_message(self, event):

print(event)

await self.send(text_data=json.dumps({

"event": event['event']

}))

前端

前端实现websocket就比较简单了。就是对websocket进行初始化,定义当websocket连接、关闭和接收消息时要执行哪些动作。

export default {

name : 'test',

data() {

return {

websock: null,

}

},

created() {

this.initWebSocket();

},

destroyed() {

this.websock.close() //离开路由之后断开websocket连接

},

methods: {

initWebSocket(){ //初始化weosocket

const wsuri = "ws://127.0.0.1:8080";

this.websock = new WebSocket(wsuri);

this.websock.onmessage = this.websocketonmessage;

this.websock.onopen = this.websocketonopen;

this.websock.onerror = this.websocketonerror;

this.websock.onclose = this.websocketclose;

},

websocketonopen(){ //连接建立之后执行send方法发送数据

let actions = {"test":"12345"};

this.websocketsend(JSON.stringify(actions));

},

websocketonerror(){//连接建立失败重连

this.initWebSocket();

},

websocketonmessage(e){ //数据接收

const redata = JSON.parse(e.data);

},

websocketsend(Data){//数据发送

this.websock.send(Data);

},

websocketclose(e){ //关闭

console.log('断开连接',e);

},

},

}

参考文章

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值