
发送文件我们先实现p2p发送消息,我们用php swoole搭建一个信令服务器
<?php
$userlist = [];
$server = new Swoole\Websocket\Server("0.0.0.0", 9502, SWOOLE_BASE, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$server->set([
'ssl_cert_file' => '/data/cert/6284283_web.debug.only.bfw.wiki.pem',
'ssl_key_file' => '/data/cert/6284283_web.debug.only.bfw.wiki.key',
]);
$server->on('open', function($server, $req) {
$_get = $req->get;
$_username = $_get['username'];
global $userlist;
$userlist[$_username] = $req->fd;
echo "connection open: {$req->fd}{$_username}\n";
});
$server->on('message', function($server, $frame) {
$data = json_decode($frame->data, true);
//消息类型
$type = $data["type"];
$_ret = ["type" => $type];
//to user
$toUser = $data["toUser"];
$fromUser = $data["fromUser"];
$msg = isset($data["msg"])?$data["msg"]:"";
//msg
$sdp = isset($data["sdp"])?$data["sdp"]:"";
//sdp
$iceCandidate = isset($data["iceCandidate"])?$data["iceCandidate"]:"";
//ice
//对方挂断
if ("hangup" == $type) {
$_ret['fromUser'] = $fromUser;
$_ret['msg'] = "对方挂断";
}
//视频通话请求
if ("call_start" == $type) {
$_ret['fromUser'] = $fromUser;
$_ret['msg'] = "1";
}
//视频通话请求回应
if ("call_back" == $type) {
$_ret['fromUser'] = $fromUser;
$_ret['msg'] = $msg;
}
//offer
if ("offer" == $type) {
$_ret['fromUser'] = $toUser;
$_ret['sdp'] = $sdp;
}
//answer
if ("answer" == $type) {
$_ret['fromUser'] = $toUser;
$_ret['sdp'] = $sdp;
}
//ice
if ("_ice" == $type) {
$_ret['fromUser'] = $toUser;
$_ret['iceCandidate'] = $iceCandidate;
}
if ($toUser != "") {
global $userlist;
if (!isset($userlist[$toUser])) {
$_ret['msg'] = "Sorry,呼叫的用户不在线!";
$_ret['type'] = "call_back";
$_ret['fromUser'] = "系统消息";
$_senddata = json_encode($_ret);
$server->push($frame->fd, $_senddata);
} else {
foreach ($userlist as $key => $val) {
if ($key == $toUser) {
$_senddata = json_encode($_ret);
echo "send message: {$_senddata}\n";
$server->push($val, $_senddata);
}
}
}
}
// echo "received message: {$frame->data}\n";
});
$server->on('close', function($server, $fd) {
echo "connection close: {$fd}\n";
});
$server->start();在使用html实现点击查看全文
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
<style>
</style>
</head>
<body>
<div id="main">
<div id="messhis">
</div>
<div id="buttons">
<span id="yourno"></span>
<input id="toUser" placeholder="输入在线好友账号" /><br/>
<textarea id="message">你好</textarea>
<button id="connect">链接</button>
<button id="send">发送</button>
</div>
</div>
<script type="text/javascript" >
var icecanarr=[];
var dataChannel=null;
let username = randomString(6);
document.getElementById('yourno').innerHTML="您的账户名是:"+username;
let localVideo = document.getElementById('localVideo');
let remoteVideo = document.getElementById('remoteVideo');
let websocket = null;
let peer = null;
WebSocketInit();
ButtonFunInit();
function randomString(len) {
len = len || 32;
var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
var maxPos = $chars.length;
var pwd = '';
for (i = 0; i < len; i++) {
pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
}
return pwd;
}
/* WebSocket */
function WebSocketInit(){
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("wss:/web.debug.only.bfw.wiki:9502/?username="+username);
} else {
alert("当前浏览器不支持WebSocket!");
}
//连接发生错误的回调方法
websocket.onerror = function (e) {
alert("WebSocket连接发生错误!");
};
//连接关闭的回调方法
websocket.onclose = function () {
console.error("WebSocket连接关闭");
};
//连接成功建立的回调方法
websocket.onopen = function () {
console.log("WebSocket连接成功");
};
//接收到消息的回调方法
websocket.onmessage = async function (event) {
let { type, fromUser, msg, sdp, iceCandidate } = JSON.parse(event.data.replace(/\n/g,"\\n").replace(/\r/g,"\\r"));
console.log(type);
if (type === 'hangup') {
console.log(msg);
document.getElementById('hangup').click();
return;
}
if (type === 'call_start') {
let msg = "0"
document.getElementById('toUser').value = fromUser;
WebRTCInit();
msg = "1"
websocket.send(JSON.stringify({
type:"call_back",
toUser:fromUser,
fromUser:username,
msg:msg
}));
return;
}
if (type === 'call_back') {
if(msg === "1"){
let offer = await peer.createOffer();
await peer.setLocalDescription(offer);
let newOffer = offer.toJSON();
newOffer["fromUser"] = username;
newOffer["toUser"] = document.getElementById('toUser').value;
websocket.send(JSON.stringify(newOffer));
}else if(msg === "0"){
alert(document.getElementById('toUser').value + "拒绝视频通话");
document.getElementById('hangup').click();
}else{
alert(msg);
document.getElementById('hangup').click();
}
return;
}
if (type === 'offer') {
await peer.setRemoteDescription(new RTCSessionDescription({ type, sdp }));
for (let i = 0; i < icecanarr.length; i++) {
peer.addIceCandidate(icecanarr[i]);
}
console.log(peer.remoteDescription)
let answer = await peer.createAnswer();
let newAnswer = answer.toJSON();
newAnswer["fromUser"] = username;
newAnswer["toUser"] = document.getElementById('toUser').value;
websocket.send(JSON.stringify(newAnswer));
await peer.setLocalDescription(answer);
// 创建数据通道
//ice
return;
}
if (type === 'answer') {
console.log(type)
console.log(sdp)
peer.setRemoteDescription(new RTCSessionDescription({ type, sdp }));
for (let i = 0; i < icecanarr.length; i++) {
peer.addIceCandidate(icecanarr[i]);
}
return;
}
if (type === '_ice') {
if(peer.remoteDescription!=null){
peer.addIceCandidate(iceCandidate);
}else{
icecanarr.push(iceCandidate);
}
// console.log(iceCandidate);
// peer.addIceCandidate(iceCandidate);
return;
}
}
}
/* WebRTC */
function WebRTCInit(){
const config = {
'iceServers': [
{
'url': 'stun:web.debug.only.bfw.wiki:3478',
},
{
'url': 'turn:web.debug.only.bfw.wiki:3478',
'username': 'bfw',
'credential': 'bfw'
}
]
};
peer = new RTCPeerConnection(config);
dataChannel = peer.createDataChannel("textChannel");
// 监听数据通道的打开事件
dataChannel.onopen = () => {
console.log("数据通道已打开发送消息");
// 可以开始发送文本消息
dataChannel.send("Hello, P2P!");
};
// 监听数据通道的错误事件
dataChannel.onerror = (error) => {
console.error("数据通道错误:", error);
};
// 监听数据通道的关闭事件
dataChannel.onclose = () => {
console.log("数据通道已关闭");
};
// 监听接收到的文本消息
dataChannel.onmessage = (event) => {
const receivedMessage = event.data;
appendmess(receivedMessage)
console.log("接收到的消息:", receivedMessage);
};
//track
// 监听数据通道的消息事件
peer.ondatachannel = (event) => {
const recdataChannel = event.channel;
// 监听数据通道的打开事件
recdataChannel.onopen = () => {
console.log("数据通道已打开");
};
// 监听数据通道的错误事件
recdataChannel.onerror = (error) => {
console.error("数据通道错误:", error);
};
// 监听数据通道的关闭事件
recdataChannel.onclose = () => {
console.log("数据通道已关闭");
};
// 监听接收到的文本消息
recdataChannel.onmessage = (event) => {
const receivedMessage = event.data;
appendmess(receivedMessage)
console.log("接收到的消息:", receivedMessage);
};
};
peer.onicecandidate = function (e) {
if (e.candidate) {
websocket.send(JSON.stringify({
type: '_ice',
toUser:document.getElementById('toUser').value,
fromUser:username,
iceCandidate: e.candidate
}));
}
};
}
/* 按钮事件 */
function ButtonFunInit(){
//链接
document.getElementById('connect').onclick = function (e){
document.getElementById('toUser').style.visibility = 'hidden';
let toUser = document.getElementById('toUser').value;
if(!toUser){
alert("请先指定好友账号,再发送消息!");
return;
}
if(peer == null){
WebRTCInit();
}
websocket.send(JSON.stringify({
type:"call_start",
fromUser:username,
toUser:toUser,
}));
}
//发送
document.getElementById('send').onclick = function (e){
let mess = document.getElementById('message').value;
dataChannel.send(mess);
appendmess(mess)
}
}
function appendmess(mess){
var listItem = document.createElement("li");
// 设置 <li> 元素的文本内容
listItem.textContent = mess;
document.getElementById('messhis').appendChild(listItem);
}
</script>
</body>
</html> 网友回复


