製作語音聊天程序源碼不是一件容易的事情,或許一些前輩的做法能夠給我們一些啓示,以下代碼爲轉載,來自雲豹科技程序員——知乎作者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 : [email protected]
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 : [email protected]
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