制作语音聊天程序源码不是一件容易的事情,或许一些前辈的做法能够给我们一些启示,以下代码为转载,来自云豹科技程序员——知乎作者111,原文链接如上,感谢授权
首先是客户端代码,这些代码主要实现内容有:
- 当用户进入退出直播间时,其他人会收到通知
- 聊天室内消息互通
- 管理员功能
具体代码如下:
# client.py
from socket import *
import os
import sys
用户发送消息
def send_msg(s, name, addr):
while True:
text = input('发言:')
# 如果输入quit表示退出
if text.strip() == 'quit':
msg = 'Q ' + name
s.sendto(msg.encode(), addr)
sys.exit('退出聊天室')
msg = 'C %s %s' % (name, text)
s.sendto(msg.encode(), addr)
接收消息
def recv_msg(s):
while True:
data, addr = s.recvfrom(2048)
if data.decode() == 'EXIT':
sys.exit(0)
print(data.decode() + '\n发言:', end = " ")
创建套接字,登录,创建子进程
def main():
# 从命令行获取服务端地址
if len(sys.argv) < 3:
print('argv is error')
return
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST, PORT)
# 创建套接字
s = socket(AF_INET, SOCK_DGRAM)
while True:
name = input('请输入姓名:')
msg = 'L ' + name
# 发送登录请求
s.sendto(msg.encode(), ADDR)
# 等待服务器回复
data, addr = s.recvfrom(1024)
if data.decode() == 'OK':
print('您已进入聊天室')
break
else:
# 不成功服务端会回复不允许登录原因
print(data.decode())
# 创建父子进程
pid = os.fork()
if pid < 0:
sys.exit('创建子进程失败')
elif pid == 0:
send_msg(s, name, ADDR)
else:
recv_msg(s)
if __name__ == '__main__':
main()
其次是服务端代码
#!/usr/bin/env python3
#coding = utf-8
'''
name = lisimeng
email : 18844630644@163.com
data = 2018-9
instroduce: chatroom server
env : python3.5
'''
from socket import *
import os
import sys
def do_login(s, user, name, addr):
if (name in user) or name == '管理员':
s.sendto('该用户已存在'.encode(), addr)
return
# retrun到 do_parent()中的do_login(s, user, msgList[1], addr)
s.sendto(b'OK', addr)
通知其他人
msg = '\n欢迎进入%s 聊天室' % name
for i in user:
s.sendto(msg.encode(), user[i])
# 插入用户
user[name] = addr
服务端转发聊天消息
def do_chat(s, user, name, text):
msg = '\n%s 说: %s' % (name, text)
for i in user:
if i != name:
s.sendto(msg.encode(), user[i])
退出聊天室
def do_quit(s, user, name):
msg = '\n' + name + '退出聊天室'
for i in user:
if i == name:
s.sendto(b'EXIT', user[i])
else:
s.sendto(msg.encode(), user[i])
# 从字典中删除用户
del user[name]
接收客户端请求
def do_parent(s):
# 存储结构{'zhangsan':('0.0.0.0',9999)}
user = {}
while True:
msg, addr = s.recvfrom(1024)
msgList = msg.decode().split(' ')
# 区分请求类型
if msgList[0] == 'L':
do_login(s, user, msgList[1], addr)
elif msgList[0] == 'C':
do_chat(s, user, msgList[1], ' '.join(msgList[2:]))
elif msgList[0] == 'Q':
do_quit(s, user, msgList[1])
做管理员喊话
def do_child(s, addr):
while True:
msg = input('管理员消息:')
msg = 'C 管理员' + msg
s.sendto(msg.encode(), addr)
创建网络,创建进程,调用功能函数
def main():
# server address
ADDR = (‘0.0.0.0’, 8888)
# 创建套接字
s = socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(ADDR)
# 创建一个单独的进程处理管理员的喊话功能
pid = os.fork()
if pid < 0:
sys.exit('创建进程失败')
elif pid == 0:
do_child(s, ADDR)
else:
do_parent(s)
if __name__ == "__main__":
main()
到这里,客户端代码便编写完毕,接下来准备编写服务端代码:
#!/usr/bin/env python3
#coding = utf-8
'''
name = lisimeng
email : 18844630644@163.com
data = 2018-9
instroduce: chatroom server
env : python3.5
'''
from socket import *
import os
import sys
def do_login(s, user, name, addr):
if (name in user) or name == '管理员':
s.sendto('该用户已存在'.encode(), addr)
return
# retrun到 do_parent()中的do_login(s, user, msgList[1], addr)
s.sendto(b'OK', addr)
# 通知其他人
msg = '\n欢迎进入%s 聊天室' % name
for i in user:
s.sendto(msg.encode(), user[i])
# 插入用户
user[name] = addr
服务端转发聊天消息
def do_chat(s, user, name, text):
msg = '\n%s 说: %s' % (name, text)
for i in user:
if i != name:
s.sendto(msg.encode(), user[i])
退出聊天室
`def do_quit(s, user, name):
msg = '\n' + name + '退出聊天室'
for i in user:
if i == name:
s.sendto(b'EXIT', user[i])
else:
s.sendto(msg.encode(), user[i])
# 从字典中删除用户
del user[name]`
接收客户端请求
def do_parent(s):
# 存储结构{'zhangsan':('0.0.0.0',9999)}
user = {}
while True:
msg, addr = s.recvfrom(1024)
msgList = msg.decode().split(' ')
# 区分请求类型
if msgList[0] == 'L':
do_login(s, user, msgList[1], addr)
elif msgList[0] == 'C':
do_chat(s, user, msgList[1], ' '.join(msgList[2:]))
elif msgList[0] == 'Q':
do_quit(s, user, msgList[1])
# 做管理员喊话
def do_child(s, addr):
while True:
msg = input('管理员消息:')
msg = 'C 管理员' + msg
s.sendto(msg.encode(), addr)
创建网络,创建进程,调用功能函数
def main():
# server address
ADDR = ('0.0.0.0', 8888)# 创建套接字
s = socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(ADDR)
# 创建一个单独的进程处理管理员的喊话功能
pid = os.fork()
if pid < 0:
sys.exit('创建进程失败')
elif pid == 0:
do_child(s, ADDR)
else:
do_parent(s)
if __name__ == "__main__":
main()
接下来,是关于语音聊天程序源码搭建相关事宜
安装好swoole后开始搭建
前端
<meta charset="UTF-8">
<title>聊天室</title></head><style>
#set_name{
margin: auto;
text-align: center;
}</style><body><h3 style="text-align: center">亮亮的聊天室</h3><div id="set_name">
姓名:<input name="name" id="name"><input type="button" onclick="set_name();" value="进入群聊"></div><div id="chat" style="width: 600px; border: red 1px solid;margin: auto;display: none">
<div id="sayContent" style="height: 300px;border-bottom: silver 1px dashed;">
</div>
<div style="height: 75px;margin-top: 10px">
<textarea id="content" style="height: 50px;width: 480px;background-color: #00a0e9;float: left;"></textarea>
<button id="submit" style="float: right;height: 55px;width:50px;margin-right:45px;display: block;" onclick="send_msg();">发送</button>
</div></div><script>
var name = ws = '' ;
//执行websock
function chat() {
var wsserver = 'ws://47.94.11.195:443';
//调用WebSocket对象建立连接
//ws wss: // ip:port(字符串)
ws = new WebSocket(wsserver);
//获取聊天内容展示窗口
var sayContent = document.getElementById('sayContent');
//onopen监听连接打开
ws.onopen = function (v) {
var user = new Object();
user.name = name;
user.type = 1;//对用户设置姓名
var json = JSON.stringify(user);
ws.send(json);//发送数据
}
//onmessage监听服务器数据推送
ws.onmessage = function (v) {
var html = sayContent.innerHTML;
sayContent.innerHTML = html + "<br>"+v.data;
}
//监听连接关闭
ws.onclose = function (v) {
var html = sayContent.innerHTML;
sayContent.innerHTML = html + "<br>聊天室已关闭!";
}
}
//设置用户名
function set_name() {
name = document.getElementById('name').value;
if(name == ''){
alert('请输入用户名!');
return false;
}
document.getElementById('set_name').style.display='none';
document.getElementById('chat').style.display='block';
chat();
}
function send_msg() {
var content = document.getElementById('content');
if(content.value == ''){
alert('请输入聊天内容!');
return false;
}
var msg = new Object();
msg.content = content.value;
msg.type = 2;
var str = JSON.stringify(msg);
ws.send(str);
}</script></body></html>
后台
$server = new swoole_websocket_server("0.0.0.0", 443);
$server->users = [];
$server->on('open', function (swoole_websocket_server $server, $request) {
$server->users[$request->fd]['id'] = $request->fd;
});
$server->on('message', function (swoole_websocket_server $server, $frame) {
$data = json_decode($frame->data,true);
if($data['type'] == 1){
$server->users[$frame->fd]['name']=$data['name'];
$server->push($frame->fd,'欢迎您('.$data['name'].')进入聊天室!');
}else{
foreach($server->users as $v){
$server->push($v['id'], $server->users[$frame->fd]['name'].'说:'.$data['content']);
}
}
});
$server->on('close', function ($ser, $fd) {
file_put_contents('qq.txt',$server->users[$frame->fd],FILE_APPEND);
unset($server->users[$frame->fd]);
});
$server->start();
<?php# 定义 clientFds 数组 保存所有 websocket 连接
$clientFds = [];
创建 websocket 服务
$server = new swoole_websocket_server("0.0.0.0", 8080);# 握手成功 触发回调函数
$server->on('open', function (swoole_websocket_server $server, $request) use (&$clientFds) {
# echo "server: handshake success with fd{$request->fd}\n";
# 将所有客户端连接标识,握手成功后保存到数组中
$clientFds[] = $request->fd;
});# 收到消息 触发回调函数
$server->on('message', function (swoole_websocket_server $server, $frame) use (&$clientFds) {
# echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
# $server->push($frame->fd, "this is server");
# 当有用户发送信息,发送广播通知所有用户
foreach ($clientFds as $fd) {
$server->push($fd, $frame->data);
}
});# 关闭连接 触发回调函数
$server->on('close', function ($ser, $fd) use (&$clientFds) {
# echo "client {$fd} closed\n";
# 关闭会话 销毁标识 fd
# 根据 value 去数组中找对应的 key
$res = array_search($fd, $clientFds, true);
unset($clientFds[$res]);
});# 启动 websocket 服务
$server->start();
<!DOCTYPE html><html lang="en"><head>
<meta charset="UTF-8">
<title>WebSocket 聊天室</title></head><body><div id="main" style="width:600px;height: 200px; overflow: auto;border: solid 2px black;"></div><textarea id="textarea"></textarea><br/><input type="button" value="发送数据" onclick="send()"><script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script><script type="text/javascript">
var name =prompt("请输入您的昵称","匿名者"); //弹出 input 框
// 打开一个 web socket
var ws = new WebSocket("ws://ip:8080");
ws.onopen = function() {
console.log("连接成功");
};
//收到消息 触发回调
ws.onmessage = function (evt) {
var data = evt.data;
console.log("收到 socket 服务消息,内容:" + data);
$('#main').append("<p>" + data + "</p>");
};
function send() {
var data = document.getElementById('textarea').value;
ws.send(name+ ":"+ data);
}
ws.onclose = function() {
// 关闭 websocket
console.log("连接已关闭...");
};</script></body></html>
最后,关于语音聊天程序源码如何上架请参考我的上一篇文章:https://blog.csdn.net/weixin_45629732/article/details/103309906