无法与作为对等节点的 Node JS 服务器建立 WebRTC 连接
Unable to establish WebRTC connection with Node JS server as a peer
我正在尝试使用 WebRTC 数据通道将从 canvas 捕获的图像发送到我的 NodeJS 后端服务器。那就是我正在尝试使我的服务器成为对等服务器。但是由于某些原因,我无法建立连接。
客户端
async function initChannel()
{
const offer = await peer.createOffer();
await peer.setLocalDescription(offer);
const response = await fetch("/connect", {
headers: {
'Content-Type': 'application/json',
},
method: 'post',
body: JSON.stringify({ sdp: offer, id: Math.random() })
}).then((res) => res.json());
peer.setRemoteDescription(response.sdp);
const imageChannel = peer.createDataChannel("imageChannel", { ordered: false, maxPacketLifeTime: 100 });
peer.addEventListener("icecandidate", console.log);
peer.addEventListener("icegatheringstatechange",console.log);
// drawCanvas function draws images got from the server.
imageChannel.addEventListener("message", message => drawCanvas(remoteCanvasCtx, message.data, imageChannel));
// captureImage function captures and sends image to server using imageChannel.send()
imageChannel.addEventListener("open", () => captureImage(recordCanvasCtx, recordCanvas, imageChannel));
}
const peer = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.stunprotocol.org:3478" }] });
initChannel();
这里 captureImage
和 drawCanvas
都没有被调用。
服务器端
import webrtc from "wrtc"; // The wrtc module ( npm i wrtc )
function handleChannel(channel)
{
console.log(channel.label); // This function is not being called.
}
app.use(express.static(resolve(__dirname, "public")))
.use(bodyParser.json())
.use(bodyParser.urlencoded({ extended: true }));
app.post("/connect", async ({ body }, res) =>
{
console.log("Connecting to client...");
let answer, id = body.id;
const peer = new webrtc.RTCPeerConnection({ iceServers: [{ urls: "stun:stun.stunprotocol.org:3478" }] });
await peer.setRemoteDescription(new webrtc.RTCSessionDescription(body.sdp));
await peer.setLocalDescription(answer = await peer.createAnswer());
peer.addEventListener("datachannel",handleChannel)
return res.json({ sdp: answer });
});
app.listen(process.env.PORT || 2000);
此处 post 请求处理良好,但从未调用 handleChannel
。
当我 运行 这样做时,我没有收到任何错误,但是当我检查连接状态时,它永远显示“新”。我控制台记录了远程和本地描述,它们似乎都已设置好。
我在这里做错了什么?
我是 WebRTC 的新手,我什至不确定这是否是连续向服务器发送图像(用户网络摄像头馈送的帧)和从服务器返回的正确方法,如果有人能告诉我更好的方法,请做。
还有一件事,我如何通过数据通道以低延迟发送图像 blob(从 canvas.toBlob()
获得)。
在朋友的帮助下,我终于弄明白了。问题是我必须在调用 peer.createOffer()
之前创建 DataChannel。 peer.onnegotiationneeded
仅在创建频道后调用回调。通常,当您通过将流传递给 WebRTC 创建媒体频道(音频或视频)时,会发生这种情况,但在这里,由于我不使用它们,所以我必须这样做。
客户端
const peer = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.l.google.com:19302" }] });
const imageChannel = peer.createDataChannel("imageChannel");
imageChannel.onmessage = ({ data }) =>
{
// Do something with received data.
};
imageChannel.onopen = () => imageChannel.send(imageData);// Data channel opened, start sending data.
peer.onnegotiationneeded = initChannel
async function initChannel()
{
const offer = await peer.createOffer();
await peer.setLocalDescription(offer);
// Send offer and fetch answer from the server
const { sdp } = await fetch("/connect", {
headers: {
"Content-Type": "application/json",
},
method: "post",
body: JSON.stringify({ sdp: peer.localDescription }),
})
.then(res => res.json());
peer.setRemoteDescription(new RTCSessionDescription(sdp));
}
服务器
收到客户通过 post 请求发送的报价。为其创建一个答案并作为回复发送。
app.post('/connect', async ({ body }, res) =>
{
const peer = new webrtc.RTCPeerConnection({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
});
console.log('Connecting to client...');
peer.ondatachannel = handleChannel;
await peer.setRemoteDescription(new webrtc.RTCSessionDescription(body.sdp));
await peer.setLocalDescription(await peer.createAnswer());
return res.json({ sdp: peer.localDescription });
});
处理数据通道的函数。
/**
* This function is called once a data channel is ready.
*
* @param {{ type: 'datachannel', channel: RTCDataChannel }} event
*/
function handleChannel({ channel })
{
channel.addEventListener("message", {data} =>
{
// Do something with data received from client.
});
// Can use the channel to send data to client.
channel.send("Hi from server");
}
事情是这样的:
- 客户端创建数据通道。
- 创建数据通道后
onnegotiationneeded
调用回调。
- 客户端创建报价并将其发送到服务器(作为 post 请求)。
- 服务器接收报价并创建答案。
- 服务器将答案发送回客户端(作为 post 响应)。
- 客户端使用收到的应答完成初始化。
ondatachannel
在服务器和客户端上调用回调。
我在这里使用 post 请求来交换报价和答案,但如果您喜欢的话,使用 Web Socket 做同样的事情应该相当容易。
我正在尝试使用 WebRTC 数据通道将从 canvas 捕获的图像发送到我的 NodeJS 后端服务器。那就是我正在尝试使我的服务器成为对等服务器。但是由于某些原因,我无法建立连接。
客户端
async function initChannel()
{
const offer = await peer.createOffer();
await peer.setLocalDescription(offer);
const response = await fetch("/connect", {
headers: {
'Content-Type': 'application/json',
},
method: 'post',
body: JSON.stringify({ sdp: offer, id: Math.random() })
}).then((res) => res.json());
peer.setRemoteDescription(response.sdp);
const imageChannel = peer.createDataChannel("imageChannel", { ordered: false, maxPacketLifeTime: 100 });
peer.addEventListener("icecandidate", console.log);
peer.addEventListener("icegatheringstatechange",console.log);
// drawCanvas function draws images got from the server.
imageChannel.addEventListener("message", message => drawCanvas(remoteCanvasCtx, message.data, imageChannel));
// captureImage function captures and sends image to server using imageChannel.send()
imageChannel.addEventListener("open", () => captureImage(recordCanvasCtx, recordCanvas, imageChannel));
}
const peer = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.stunprotocol.org:3478" }] });
initChannel();
这里 captureImage
和 drawCanvas
都没有被调用。
服务器端
import webrtc from "wrtc"; // The wrtc module ( npm i wrtc )
function handleChannel(channel)
{
console.log(channel.label); // This function is not being called.
}
app.use(express.static(resolve(__dirname, "public")))
.use(bodyParser.json())
.use(bodyParser.urlencoded({ extended: true }));
app.post("/connect", async ({ body }, res) =>
{
console.log("Connecting to client...");
let answer, id = body.id;
const peer = new webrtc.RTCPeerConnection({ iceServers: [{ urls: "stun:stun.stunprotocol.org:3478" }] });
await peer.setRemoteDescription(new webrtc.RTCSessionDescription(body.sdp));
await peer.setLocalDescription(answer = await peer.createAnswer());
peer.addEventListener("datachannel",handleChannel)
return res.json({ sdp: answer });
});
app.listen(process.env.PORT || 2000);
此处 post 请求处理良好,但从未调用 handleChannel
。
当我 运行 这样做时,我没有收到任何错误,但是当我检查连接状态时,它永远显示“新”。我控制台记录了远程和本地描述,它们似乎都已设置好。 我在这里做错了什么?
我是 WebRTC 的新手,我什至不确定这是否是连续向服务器发送图像(用户网络摄像头馈送的帧)和从服务器返回的正确方法,如果有人能告诉我更好的方法,请做。
还有一件事,我如何通过数据通道以低延迟发送图像 blob(从 canvas.toBlob()
获得)。
在朋友的帮助下,我终于弄明白了。问题是我必须在调用 peer.createOffer()
之前创建 DataChannel。 peer.onnegotiationneeded
仅在创建频道后调用回调。通常,当您通过将流传递给 WebRTC 创建媒体频道(音频或视频)时,会发生这种情况,但在这里,由于我不使用它们,所以我必须这样做。
客户端
const peer = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.l.google.com:19302" }] });
const imageChannel = peer.createDataChannel("imageChannel");
imageChannel.onmessage = ({ data }) =>
{
// Do something with received data.
};
imageChannel.onopen = () => imageChannel.send(imageData);// Data channel opened, start sending data.
peer.onnegotiationneeded = initChannel
async function initChannel()
{
const offer = await peer.createOffer();
await peer.setLocalDescription(offer);
// Send offer and fetch answer from the server
const { sdp } = await fetch("/connect", {
headers: {
"Content-Type": "application/json",
},
method: "post",
body: JSON.stringify({ sdp: peer.localDescription }),
})
.then(res => res.json());
peer.setRemoteDescription(new RTCSessionDescription(sdp));
}
服务器
收到客户通过 post 请求发送的报价。为其创建一个答案并作为回复发送。
app.post('/connect', async ({ body }, res) =>
{
const peer = new webrtc.RTCPeerConnection({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
});
console.log('Connecting to client...');
peer.ondatachannel = handleChannel;
await peer.setRemoteDescription(new webrtc.RTCSessionDescription(body.sdp));
await peer.setLocalDescription(await peer.createAnswer());
return res.json({ sdp: peer.localDescription });
});
处理数据通道的函数。
/**
* This function is called once a data channel is ready.
*
* @param {{ type: 'datachannel', channel: RTCDataChannel }} event
*/
function handleChannel({ channel })
{
channel.addEventListener("message", {data} =>
{
// Do something with data received from client.
});
// Can use the channel to send data to client.
channel.send("Hi from server");
}
事情是这样的:
- 客户端创建数据通道。
- 创建数据通道后
onnegotiationneeded
调用回调。 - 客户端创建报价并将其发送到服务器(作为 post 请求)。
- 服务器接收报价并创建答案。
- 服务器将答案发送回客户端(作为 post 响应)。
- 客户端使用收到的应答完成初始化。
ondatachannel
在服务器和客户端上调用回调。
我在这里使用 post 请求来交换报价和答案,但如果您喜欢的话,使用 Web Socket 做同样的事情应该相当容易。