Вопрос или проблема
Я пытаюсь отправить данные через datachannel webrtc. Ниже мой код
//код клиентской стороны
// Подключение к WebSocket серверу
var ID = null;
const ws = new WebSocket("ws://localhost:8080");
// Настройка пирового соединения (UDP)
const localConnection = new RTCPeerConnection();
const dataChannel = localConnection.createDataChannel("sendChannel");
document.getElementById("Send").addEventListener('click' , function(){
console.log("Пытаюсь отправить сообщение...");
dataChannel.send("Привет")
})
// console.log(Object.getPrototypeOf(ws));
ws.onopen = () => {
console.log("Подключено к серверу");
//const dataChannel = connection.createDataChannel("channel");
localConnection.onicecandidate = (e) => {
console.log("Новый ICE кандидат!" , localConnection.localDescription.type);
ws.send(JSON.stringify({
type: "create"+ localConnection.localDescription.type,
data: {
id: ID,
sdp: localConnection.localDescription
}
}))
/* ws.send(JSON.stringify({
type: "ICE",
data: {
sdp: localConnection.localDescription
}
}));*/
//ws.send("[Сервер]: Новый Ice кандидат");
};
localConnection.onicecandidateerror = (e) => {
console.warn("Ошибка: ICE кандидат", e);
};
dataChannel.onmessage = (e) =>
console.log("сообщение получено!!!" + e.data);
dataChannel.onopen = (e) => console.log("открыто!!!!");
dataChannel.onclose = (e) => console.log("закрыто!!!!!!");
// Отправить сообщение серверу
ws.send(JSON.stringify({type: "findLobby" , "message": null}));
};
ws.onclose = () => {
console.log("Отключено от сервера");
};
ws.onmessage = (event) => {
// console.log(Получено сообщение от сервера: ${typeof event.data});
//if (typeof event.data !== "object") return;
var data = JSON.parse(event.data);
switch (data.type) {
case "createOffer":
console.log("Создание предложения!");
localConnection.createOffer()
.then(o => {
//console.log(o);
localConnection.setLocalDescription(o);
/* ws.send(JSON.stringify({
type: "createOffer",
data: {
sdp: o
}
}))*/
});
break;
case "createAnswer":
console.log("Создание ответа!");
console.log("Общедоступная сессия найдена: Вы сейчас подключаетесь...");
localConnection.setRemoteDescription(data.data[1].sdp).then(a=> console.log(localConnection.remoteDescription, "Удаленное соединение настроено"))
localConnection.createAnswer().then(a=>{
console.log(a)
localConnection.setLocalDescription(a).then(()=> {
console.log('Локальное описание настроено: ',localConnection.localDescription)
ws.send(JSON.stringify({
type: "answer",
data: {
sessionid: data.data[0],
sdp: localConnection.localDescription
}
}))
});
});
break;
case "acceptAnswer":
console.log("Принять ответ: ",event.data)
let datax = JSON.parse(event.data);
let answer = datax.data.sdp;
localConnection.setRemoteDescription(answer).then(a => {
console.log("Установление соединения...");
//dataChannel.send(JSON.stringify({message: "Привет" , data: datax}))
})
break;
case "message":
console.log(event.data)
break;
case "newclient":
console.log("Новый клиент id" , event.data);
ID = JSON.parse(event.data).id;
break;
default:
console.log("Неверный тип");
break;
}
};
Код серверной стороны (websocket)
const WebSocket = require('ws');
// Создание WebSocket сервера, прослушивающего порт 8080
const wss = new WebSocket.Server({ port: 8080 });
const freeUsers = new Map();
const connected = [];
const clients = new Map();
class PublicLobby{
constructor(id){
this.id = id;
this.players = new Map();
this.host = null;
}
}
wss.on('connection', (ws) => {
var sessionid = generateUniqueId();
clients.set(sessionid , {
isJoined: false,
isFree: true,
ws: ws,
});
// Отправить приветственное сообщение клиенту
ws.send(JSON.stringify(
{
type: 'newclient',
id: sessionid,
}
))
ws.send(JSON.stringify({type: 'message' , message: 'Добро пожаловать на WebSocket сервер!'}));
// Слушать сообщения от клиента
ws.on('message', (message) => {
let m = JSON.parse(message);
console.log("Свободные пользователи:" , freeUsers);
//console.log("клиенты:" , clients);
switch (m.type) {
case "createoffer":
if(clients.has(m.data.id)){
let player = clients.get(m.data.id)
player.sdp = m.data.sdp;
if(freeUsers.has(m.data.id)){
freeUsers.get(m.data.id).sdp = m.data.sdp;
}
else{
freeUsers.set(m.data.id , {
isJoined: false,
isFree: true,
ws: player.ws,
...m.data});
ws.send(JSON.stringify({type: "message" , message: "Создана новая сессия!" }));
}
}
break;
case "ICE":
// console.log("Ice data:" , m.data);
ws.send(JSON.stringify({type: "acceptAnswer" , message: "Ice ответ" , data: m.data}))
break;
case "createanswer":
//console.log(m.data);
const freeUser = freeUsers.entries().next().value;
if (freeUser && !freeUser[1].ans) {
freeUser[1].ws.send(JSON.stringify({ type: "acceptAnswer", message: "Ответ от клиента", data: m.data }));
freeUser[1].ans = true;
}
break;
case "findLobby":
if(freeUsers.size > 0)
ws.send(JSON.stringify({ type: "createAnswer", message:"Лобби найдено, вы сейчас присоединяетесь.." , data: freeUsers.entries().next().value}));
else
ws.send(JSON.stringify({ type: "createOffer", message:"Сессия не найдена (создание новой публичной сессии...)"}))
break;
default:
break;
}
});
// Обработка отключения клиента
ws.on('close', () => {
// freeUsers.get()
console.log('Клиент отключен');
});
});
function generateUniqueId() {
return `session_${Math.random().toString(36).substr(2, 9)}`;
}
console.log('WebSocket сервер работает на ws://localhost:8080');
Я пытаюсь отправить данные через канал данных WEBRTC для простой многопользовательской игры. datachannel
успешно открыт, но когда я пытаюсь отправить сообщение через него, ничего не происходит.
В консоли не отображается никаких ошибок.
не уверюсь, что не так с моим кодом.
Пожалуйста, помогите мне. спасибо
Ответ или решение
При работе с WebRTC Data Channel могут возникать различные проблемы, такие как: успешное открытие канала, но отсутствие отправки данных. Ваша ситуация указывает на то, что канал данных открыт, но сообщение не отправляется. Давайте рассмотрим возможные причины этой проблемы и способы их устранения.
1. Порядок установки соединения
Сначала необходимо убедиться, что оба конца соединения (клиент и сервер) корректно настроены и находятся в состоянии, когда можно обмениваться данными. Проверьте логи dataChannel.onopen
, чтобы убедиться, что канал действительно открыт перед отправкой сообщения.
dataChannel.onopen = (e) => {
console.log("Канал открыт!");
// Теперь можно отправлять данные
dataChannel.send("Hello");
};
2. Обработка сообщений
Также необходимо убедиться, что обработчик сообщений установлен корректно. В вашем коде отсутствуют фигурные скобки для функции обработки сообщений. Поправьте это, добавив их:
dataChannel.onmessage = (e) => {
console.log("Сообщение получено: " + e.data);
};
3. Параметры ICE
Проблема с отправкой сообщения может быть связана с успехом процесса формирования ICE кандидатуры (Interactive Connectivity Establishment). Эффективность ICE-кандидатов влияет на установление соединения. Убедитесь, что оба интерфейса (клиент и сервер) обмениваются всеми ICE кандидатами после установления соединения. В вашем коде это делается в обработчике onicecandidate
:
localConnection.onicecandidate = (e) => {
if (e.candidate) {
ws.send(JSON.stringify({ type: "ICE", candidate: e.candidate }));
}
};
Убедитесь, что ваш сервер корректно обрабатывает ICE кандидаты и передает их другому участнику.
4. Синхронизация SDP
При работе с SDP (Session Description Protocol) важно, чтобы оба конца соединения согласовали свои параметры. Убедитесь, что вы корректно обмениваетесь SDP описаниями, и что взаимные описания настроены перед попыткой отправить данные по каналу:
localConnection.setRemoteDescription(data.data[1].sdp)
.then(() => localConnection.createAnswer())
.then(answer => localConnection.setLocalDescription(answer));
5. Состояние WebSocket
Проверьте соединение WebSocket перед отправкой сообщений через Data Channel. Возможно, код выполняется, но соединение еще не готово. Добавьте проверку состояния WebSocket, чтобы убедиться, что он открыт:
if (ws.readyState === WebSocket.OPEN) {
// Отправляйте сообщения
}
Заключение
Для успешной передачи данных через WebRTC Data Channel убедитесь, что канал открыт, и вы правильно обрабатываете Ice кандидаты и SDP одновременно. Каждое сообщение должно отправляться только после успешного установления соединения, чтобы избежать потери данных.
Если после всех проверок проблема остается, рассмотрите использование отладочных инструментов для WebRTC, таких как webrtc-internals
, которые могут помочь вам получить дополнительную информацию о состоянии соединения.
Следуя вышеуказанным шагам, вы повысите шансы на успешную передачу данных в вашем мультиплеерном приложении. Убедитесь также, что ваша кодовая база аккуратно организована, чтобы избежать путаницы и облегчить диагностику будущих проблем.