我用django、websocket开发一个在线扑克游戏,遇到问题请教。
我的意图,也是扑克游戏的普通规则:
1、利用django自带的auth模块,建立有不同的3个用户;
2、3个用户不会同时进入牌室,等到最后(第3个用户登录并send准备好的指令)进入,后端发不同的牌给3个用户;
3、出牌时,所有用户都能看到。
这里涉及到几个概念:
1、关于群发与私发。对于发牌,是一对一向指定用户私发;对于出牌,则是群发。怎样实现群发与私发?
2、等待用户到齐,这个需要用异步模式吗?还是不一定?或者这个阶段用ajax请求?
脑袋一团雾水,请教各位的指点,最好有代码及注释说明!谢谢!
参考GPT和自己的思路:
对于你的问题,我建议使用django-socketio这个第三方库来实现websocket的功能。它可以支持异步、分组和向特定用户发送信息等功能。
对于你的需求,可以先使用django自带auth模块建立3个用户,然后在websocket连接时将用户所属的组信息传入。可以使用socketio的join_group和leave_group方法进行分组操作。
对于发牌,可以在服务器端维护一个牌局信息,然后根据用户所属的组向对应的用户发送发牌信息,例如:
from socketio.namespace import BaseNamespace
class PokerNamespace(BaseNamespace):
def on_connect(self):
# 将用户所属的组信息传入
self.group = self.request.args.get('group')
def on_ready(self, data):
# 等待所有用户准备就绪
ready_users = get_ready_users()
if len(ready_users) == 3:
# 发牌
deal_cards()
# 向各自分组的用户发送发牌信息
self.socketio.emit('deal', cards, room=self.group)
对于出牌,可以使用socketio的broadcast方法向所有用户群发出牌信息,例如:
def on_play_card(self, data):
# 出牌
play_card(data['card'])
# 群发出牌信息
self.socketio.emit('play', {'player': self.request.sid, 'card': data['card']}, broadcast=True)
至于等待用户到齐的问题,可以在客户端发送一个ready事件告知服务器用户已准备就绪,然后在服务器端维护一个列表,判断列表中的用户数是否为3,若为3则说明所有用户都准备就绪,可以进行发牌操作。可以使用socketio的emit方法向单个用户发送信息,例如:
def on_ready(self, data):
# 将准备就绪的用户添加到列表中
self.ready_users.append(self.request.sid)
# 发送准备就绪信息给用户
self.socketio.emit('ready', {'player': self.request.sid})
if len(self.ready_users) == 3:
# 发牌
deal_cards()
# 向各自分组的用户发送发牌信息
self.socketio.emit('deal', cards, room=self.group)
以上是代码示例,注意注释和自己的代码逻辑进行对比。希望可以帮助到你!
不知道你这个问题是否已经解决, 如果还没有解决的话:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Echo Test</h1>
<input id="sendTxt" type="text">
<button id="sendBtn">发送</button>
<div id="recv"></div>
<script type="text/javascript">
var websocket = new WebSocket("ws://127.0.0.1:8000/socket/");
// 引入websocket
websocket.onopen = function () {
console.log('websocket open');
let obj = JSON.stringify({ type: "set_channel", content: "222",channel:"sasaas12"})
setTimeout(()=>{websocket.send(obj)},5000)
document.getElementById("recv").innerHTML = "Connected";
}
// 结束websocket
websocket.onclose = function () {
console.log('websocket close');
}
websocket.onerror = function () {
console.log('websocket error')
}
// 接受到信息
websocket.onmessage = function (e) {
console.log(e.data);
document.getElementById("recv").innerHTML = e.data;
}
// 点击发送webscoket
document.getElementById("sendBtn").onclick = function () {
var txt = document.getElementById("sendTxt").value;
websocket.send(JSON.stringify({ type: "chagne", content: txt,channel:"sasaasa" }));
}
</script>
<!-- <script>
import { message } from 'antd';
class WebSocketClass {
constructor() {
this.instance = null;
this.connect();
}
static getInstance() {
if (!this.instance) {
this.instance = new WebSocketClass();
}
return this.instance;
}
connect() {
this.ws = new WebSocket('ws://xxxx');
this.ws.onopen = e => {
this.status = 'open';
message.info('连接成功');
console.log(`连接成功`, e);
this.heartCheck();
this.getMessage();
};
}
heartCheck() {
// 心跳机制的时间可以自己与后端约定
this.pingPong = 'ping'; // ws的心跳机制状态值
this.pingInterval = setInterval(() => {
if (this.ws.readyState === 1) {
// 检查ws为链接状态 才可发送
this.ws.send('ping'); // 客户端发送ping
}
}, 10000);
this.pongInterval = setInterval(() => {
if (this.pingPong === 'ping') {
this.closeHandle('pingPong没有改变为pong'); // 没有返回pong 重启webSocket
}
// 重置为ping 若下一次 ping 发送失败 或者pong返回失败(pingPong不会改成pong),将重启
console.log('返回pong');
this.pingPong = 'ping';
}, 20000);
}
closeHandle(e = 'err') {
// 因为webSocket并不稳定,规定只能手动关闭(调closeMyself方法),否则就重连
if (this.status !== 'close') {
console.log(`断开,重连websocket`, e);
if (this.pingInterval !== undefined && this.pongInterval !== undefined) {
// 清除定时器
clearInterval(this.pingInterval);
clearInterval(this.pongInterval);
}
this.connect(); // 重连
} else {
console.log(`websocket手动关闭,或者正在连接`);
}
}
getMessage() {
this.ws.onmessage = e => {
if (e.data === 'pong') {
this.pingPong = 'pong'; // 服务器端返回pong,修改pingPong的状态
} else {
message.info(e.data);
}
console.log(e.data);
return e.data;
};
}
close() {
clearInterval(this.pingInterval);
clearInterval(this.pongInterval);
this.status = 'close';
this.ws.send('close');
this.ws.close();
message.info('已断开连接');
console.log('close');
}
}
export default new WebSocketClass();
</script> -->
</body>
</html>