【问题标题】:WebRTC Between two pages in the same machineWebRTC 同一台机器的两个页面之间
【发布时间】:2016-05-18 01:22:54
【问题描述】:

我正在尝试实现一种机制,在 same 机器上使用 javascript 在页面之间发送文本数据(例如 JSON)。
我找到了一些代码并将其包装,但它只能在同一页面上工作。
目前我不想使用 WwebRTC 框架,只有adapter.js。

//Must include adapter.js before

var WebRTCManager = (function () {

    'use strict';

    //Ctor
    function WebRTCManagerFn() {

      console.log('WebRTCManagerFn ctor reached');

      this._events = {};

      this._localConnection = null
      this._remoteConnection = null;
      this._sendChannel = null;
      this._receiveChannel = null;
    }

    WebRTCManagerFn.prototype.addEventListener = function (name, handler)        {
      if (this._events.hasOwnProperty(name))
          this._events[name].push(handler);
      else
          this._events[name] = [handler];
    };

    WebRTCManagerFn.prototype._fireEvent = function (name, event) {
       if (!this._events.hasOwnProperty(name))
          return;

       if (!event)
          event = {};

       var listeners = this._events[name], l = listeners.length;
       for (var i = 0; i < l; i++) {
          listeners[i].call(null, event);
       }
    };

WebRTCManagerFn.prototype.createConnection = function () {
    var servers = null;
    var pcConstraint = null;
    var dataConstraint = null;

    console.log('Using SCTP based data channels');

    // SCTP is supported from Chrome 31 and is supported in FF.
    // No need to pass DTLS constraint as it is on by default in Chrome 31.
    // For SCTP, reliable and ordered is true by default.
    // Add localConnection to global scope to make it visible
    // from the browser console.
    window.localConnection = this._localConnection =
        new RTCPeerConnection(servers, pcConstraint);
    console.log('Created local peer connection object localConnection');

    this._sendChannel = this._localConnection.createDataChannel('sendDataChannel',
            dataConstraint);
    console.log('Created send data channel');
    this._localConnection.onicecandidate = this._localIceCallback.bind(this);
    this._sendChannel.onopen = this._onSendChannelStateChange.bind(this);
    this._sendChannel.onclose = this._onSendChannelStateChange.bind(this);

    // Add remoteConnection to global scope to make it visible
    // from the browser console.
    window.remoteConnection = this._remoteConnection =
        new RTCPeerConnection(servers, pcConstraint);
    console.log('Created remote peer connection object remoteConnection');
    this._remoteConnection.onicecandidate = this._remoteIceCallback.bind(this);
    this._remoteConnection.ondatachannel = this._receiveChannelCallback.bind(this);

    this._localConnection.createOffer(this._gotOfferFromLocalConnection.bind(this), this._onCreateSessionDescriptionError.bind(this));
}

WebRTCManagerFn.prototype._onCreateSessionDescriptionError = function (error) {
    console.log('Failed to create session description: ' + error.toString());
}

WebRTCManagerFn.prototype.sendMessage = function (msgText) {
    var msg = new Message(msgText);

    // Send the msg object as a JSON-formatted string.
    var data = JSON.stringify(msg);
    this._sendChannel.send(data);

    console.log('Sent Data: ' + data);
}

WebRTCManagerFn.prototype.closeDataChannels = function () {
    console.log('Closing data channels');
    this._sendChannel.close();
    console.log('Closed data channel with label: ' + this._sendChannel.label);
    this._receiveChannel.close();
    console.log('Closed data channel with label: ' + this._receiveChannel.label);
    this._localConnection.close();
    this._remoteConnection.close();
    this._localConnection = null;
    this._remoteConnection = null;
    console.log('Closed peer connections');
}

WebRTCManagerFn.prototype._gotOfferFromLocalConnection = function (desc) {
    console.log('reached _gotOfferFromLocalConnection');
    if (this && this._localConnection != 'undefined' && this._remoteConnection != 'undefined') {
        this._localConnection.setLocalDescription(desc);
        console.log('Offer from localConnection \n' + desc.sdp);
        this._remoteConnection.setRemoteDescription(desc);
        this._remoteConnection.createAnswer(this._gotAnswerFromRemoteConnection.bind(this),
            this._onCreateSessionDescriptionError.bind(this));
    }
}

WebRTCManagerFn.prototype._gotAnswerFromRemoteConnection = function (desc) {
    console.log('reached _gotAnswerFromRemoteConnection');
    if (this && this._localConnection != 'undefined' && this._remoteConnection != 'undefined') {
        this._remoteConnection.setLocalDescription(desc);
        console.log('Answer from remoteConnection \n' + desc.sdp);
        this._localConnection.setRemoteDescription(desc);
    }
}

WebRTCManagerFn.prototype._localIceCallback = function (event) {
    console.log('local ice callback');
    if (event.candidate) {
        this._remoteConnection.addIceCandidate(event.candidate,
            this._onAddIceCandidateSuccess.bind(this), this._onAddIceCandidateError.bind(this));
        console.log('Local ICE candidate: \n' + event.candidate.candidate);
    }
}

WebRTCManagerFn.prototype._remoteIceCallback = function (event) {
    console.log('remote ice callback');
    if (event.candidate) {
        this._localConnection.addIceCandidate(event.candidate,
            this._onAddIceCandidateSuccess.bind(this), this._onAddIceCandidateError.bind(this));
        console.log('Remote ICE candidate: \n ' + event.candidate.candidate);
    }
}

WebRTCManagerFn.prototype._onAddIceCandidateSuccess = function (evt) {
    debugger;
    console.log('AddIceCandidate success. evt: '+ evt);
}

WebRTCManagerFn.prototype._onAddIceCandidateError = function (error) {
    console.log('Failed to add Ice Candidate: ' + error.toString());
}

WebRTCManagerFn.prototype._receiveChannelCallback = function (event) {
    console.log('Receive Channel Callback');
    this._receiveChannel = event.channel;
    this._receiveChannel.onmessage = this._onReceiveMessageCallback.bind(this);
    this._receiveChannel.onopen = this._onReceiveChannelStateChange.bind(this);
    this._receiveChannel.onclose = this._onReceiveChannelStateChange.bind(this);
}

WebRTCManagerFn.prototype._onReceiveMessageCallback = function (event) {
    console.log('Received Message: ' + event.data);
    console.log('Received Message this is: ' + this);

    var msgObj = JSON.parse(event.data);

    this._fireEvent("messageRecieved", {
        details: {
            msg: msgObj
        }
    });
}

WebRTCManagerFn.prototype._onSendChannelStateChange = function () {
    console.log('_onSendChannelStateChange');
    var readyState = this._sendChannel.readyState;
    console.log('Send channel state is: ' + readyState);
}

WebRTCManagerFn.prototype._onReceiveChannelStateChange = function () {
    var readyState = this._receiveChannel.readyState;
    console.log('Receive channel state is: ' + readyState);
}

return WebRTCManagerFn;
})();

我的问题是如何使用 WebRTC在同一台机器上的两个页面之间传递数据

【问题讨论】:

  • 你有信令服务器吗?您对跨页面通信的问题有更具体的问题描述吗?
  • 在我的实现中,消息是在页面内接收的。我想在两个不同的页面之间进行双向通信。信令服务器是本地主机。我想我错过了一些东西...
  • 这意味着您需要一种交换消息的方法;这几乎是在同一台计算机上的两个页面之间还是在不同计算机上的两个页面之间无关。信令服务器是最佳选择。如果您能澄清确切的限制和情况,或许可以提出不同的替代方案。
  • 我只是在寻找一种在两个不同页面(应用程序)之间执行 IPC 的方法。即在它们之间传递文本数据。
  • 只是一个小问题:adapter.js 不会取代 WebRTC,它只是说明实现 WebRTC 或 ORTC 的浏览器的差异,所以如果你使用 adapter.js,你正在使用WebRTC。

标签: javascript ipc webrtc communication


【解决方案1】:

此 WebRTC 选项卡聊天演示可在同一浏览器中跨选项卡或窗口工作,无需服务器:https://jsfiddle.net/f5y48hcd/(由于 SecurityError,我放弃了使其在代码 sn-p 中工作。)

在两个窗口中打开小提琴并尝试一下。作为参考,这里是 WebRTC 代码:

var pc = new RTCPeerConnection(), dc, enterPressed = e => e.keyCode == 13;

var connect = () => init(dc = pc.createDataChannel("chat"));
pc.ondatachannel = e => init(dc = e.channel);

var init = dc => {
  dc.onopen = e => (dc.send("Hi!"), chat.select());
  dc.onclose = e => log("Bye!");
  dc.onmessage = e => log(e.data);
};

chat.onkeypress = e => {
  if (!enterPressed(e)) return;
  dc.send(chat.value);
  log("> " + chat.value);
  chat.value = "";
};

var sc = new localSocket(), send = obj => sc.send(JSON.stringify(obj));
var incoming = msg => msg.sdp &&
  pc.setRemoteDescription(new RTCSessionDescription(msg.sdp))
  .then(() => pc.signalingState == "stable" || pc.createAnswer()
    .then(answer => pc.setLocalDescription(answer))
    .then(() => send({ sdp: pc.localDescription })))
  .catch(log) || msg.candidate &&
  pc.addIceCandidate(new RTCIceCandidate(msg.candidate)).catch(log);
sc.onmessage = e => incoming(JSON.parse(e.data));

pc.oniceconnectionstatechange = e => log(pc.iceConnectionState);
pc.onicecandidate = e => send({ candidate: e.candidate });
pc.onnegotiationneeded = e => pc.createOffer()
  .then(offer => pc.setLocalDescription(offer))
  .then(() => send({ sdp: pc.localDescription }))
  .catch(log);

var log = msg => div.innerHTML += "<br>" + msg;

我用它来演示 WebRTC 数据通道。请注意,秘诀是我为此写的localSocket.js,它看起来像这样:

function localSocket() {
  localStorage.a = localStorage.b = JSON.stringify([]);
  this.index = 0;
  this.interval = setInterval(() => {
    if (!this.in) {
      if (!JSON.parse(localStorage.a).length) return;
      this.in = "a"; this.out = "b";
    }
    var arr = JSON.parse(localStorage[this.in]);
    if (arr.length <= this.index) return;
    if (this.onmessage) this.onmessage({ data: arr[this.index] });
    this.index++;
  }, 200);
  setTimeout(() => this.onopen && this.onopen({}));
}
localSocket.prototype = {
  send: function(msg) {
    if (!this.out) {
      this.out = "a"; this.in = "b";
    }
    var arr = JSON.parse(localStorage[this.out]);
    arr.push(msg);
    localStorage[this.out] = JSON.stringify(arr);
  },
  close: function() {
    clearInterval(this.interval);
  }
};

它基本上使用 localStorage 在两个选项卡之间本地模拟 Web 套接字。如果这就是您想做的全部,那么您甚至不需要 WebRTC 数据通道。

免责声明:它不是很健壮,并且依赖于准备好通信的两个页面,因此无论如何都不能用于生产。

【讨论】:

  • 这很好,但它不一定是两个选项卡,也不一定是文本消息。我正在尝试调查 Skylake 聊天。这与我想要实现的目标非常接近..
  • 这似乎可以满足您的要求。请说明您正在寻找的不是它。
  • 首先,非常感谢您的回复。本地存储存在问题,因为它将解决方案仅限于在 Chrome 浏览器上运行的应用程序。 MS edge 和 FireFox 支持 WebRTC,它们之间可能有消息交换。我正在寻找真正的跨浏览器 IPC。
  • 本地存储适用于您提到的所有浏览器。我在 Firefox 和 Chrome 中测试了这个小提琴,它对我来说都适用。您可能想要更新您的问题以反映您正在寻找的内容。 adapter.js,你提到希望使用,需要WebRTC,因此仅限于你刚才提到的浏览器。
  • 为了在同一台机器上的不同浏览器之间进行这项工作,我会在localhost 上安装一个信令服务器,正如我解释here 一样,或者修改localSocket hack 以使用 cookie(尽管我想知道是否所有 SDP 都适合 4K
猜你喜欢
  • 1970-01-01
  • 2012-03-19
  • 2016-06-23
  • 2012-03-11
  • 1970-01-01
  • 2018-09-25
  • 1970-01-01
  • 2019-05-08
  • 1970-01-01
相关资源
最近更新 更多