使用Webrtc和React Js在网络上共享跨平台的点对点文件
我们希望实现一个零思想的文件传输机制,即在两个设备或个人之间共享文件,不需要考虑如何、在哪里、为什么和什么。
“WebRTC是一个免费的开放项目,通过简单的APIs为浏览器与移动应用程序提供实时通信(RTC)功能。WebRTC组件已经进行了优化,以更好地满足这一目的。” webrtc.org 
  
    
    
  
   
     
     
   
const express = require("express");
   
     
     
    const http = require("http");
   
     
     
    const app = express();
   
     
     
    const server = http.createServer(app);
   
     
     
    const socket = require("socket.io");
   
     
     
    const io = socket(server);
   
     
     
    const users = {};
   
     
     
    const socketToRoom = {};
   
     
     
    
   
     
     
   
 io.on('connection', socket => {
   
     
     
    socket.on("join room", roomID => {
   
     
     
    if (users[roomID]) {
   
     
     
    const length = users[roomID].length;
   
     
     
    if (length === 2) {
   
     
     
    socket.emit("room full");
   
     
     
    return;
   
     
     
    }
   
     
     
    users[roomID].push(socket.id);
   
     
     
    } else {
   
     
     
    users[roomID] = [socket.id];
   
     
     
    }
   
     
     
    socketToRoom[socket.id] = roomID;
   
     
     
    const usersInThisRoom = users[roomID].filter(id => id !== socket.id);
   
     
     
    
   
     
     
   
 socket.emit("all users", usersInThisRoom);
   
     
     
    });
   
     
     
    
   
     
     
   
 socket.on("sending signal", payload => {
   
     
     
    io.to(payload.userToSignal).emit('user joined', { signal: payload.signal, callerID: payload.callerID });
   
     
     
    });
   
     
     
    
   
     
     
   
 socket.on("returning signal", payload => {
   
     
     
    io.to(payload.callerID).emit('receiving returned signal', { signal: payload.signal, id: socket.id });
   
     
     
    });
   
     
     
    
   
     
     
   
 socket.on('disconnect', () => {
   
     
     
    const roomID = socketToRoom[socket.id];
   
     
     
    let room = users[roomID];
   
     
     
    if (room) {
   
     
     
    room = room.filter(id => id !== socket.id);
   
     
     
    users[roomID] = room;
   
     
     
    socket.broadcast.emit('user left', socket.id);
   
     
     
    }
   
     
     
    });
   
     
     
    });
   
     
     
    
   
     
     
   
 server.listen(process.env.PORT || 8000, () => console.log('server is running on port 8000'));
  
    
    
    
  
    
    
  
   
     
     
   import React, { useEffect, useRef, useState } from "react";
   
     
     
   import io from "socket.io-client";
   
     
     
   import Peer from "simple-peer";
   
     
     
   import styled from "styled-components";
   
     
     
   import streamSaver from "streamsaver";
   
     
     
   
const Container = styled.div`
   
     
     
    padding: 20px;
   
     
     
    display: flex;
   
     
     
    height: 100vh;
   
     
     
    width: 90%;
   
     
     
    margin: auto;
   
     
     
    flex-wrap: wrap;
   
     
     
   `;
   
     
     
   
const worker = new Worker("../worker.js");
   
     
     
   
const Room = (props) => {
   
     
     
    const [connectionEstablished, setConnection] = useState(false);
   
     
     
    const [file, setFile] = useState();
   
     
     
    const [gotFile, setGotFile] = useState(false);
   
     
     
   
 const chunksRef = useRef([]);
   
     
     
    const socketRef = useRef();
   
     
     
    const peersRef = useRef([]);
   
     
     
    const peerRef = useRef();
   
     
     
    const fileNameRef = useRef("");
   
     
     
   
 const roomID = props.match.params.roomID;
   
     
     
   
 useEffect(() => {
   
     
     
    socketRef.current = io.connect("/");
   
     
     
    socketRef.current.emit("join room", roomID);
   
     
     
    socketRef.current.on("all users", users => {
   
     
     
    peerRef.current = createPeer(users[0], socketRef.current.id);
   
     
     
    });
   
     
     
   
 socketRef.current.on("user joined", payload => {
   
     
     
    peerRef.current = addPeer(payload.signal, payload.callerID);
   
     
     
    });
   
     
     
   
 socketRef.current.on("receiving returned signal", payload => {
   
     
     
    peerRef.current.signal(payload.signal);
   
     
     
    setConnection(true);
   
     
     
    });
   
     
     
   
 socketRef.current.on("room full", () => {
   
     
     
    alert("room is full");
   
     
     
    })
   
     
     
   
 }, []);
   
     
     
   
 function createPeer(userToSignal, callerID) {
   
     
     
    const peer = new Peer({
   
     
     
    initiator: true,
   
     
     
    trickle: false,
   
     
     
    });
   
     
     
   
 peer.on("signal", signal => {
   
     
     
    socketRef.current.emit("sending signal", { userToSignal, callerID, signal });
   
     
     
    });
   
     
     
   
 peer.on("data", handleReceivingData);
   
     
     
   
 return peer;
   
     
     
    }
   
     
     
   
 function addPeer(incomingSignal, callerID) {
   
     
     
    const peer = new Peer({
   
     
     
    initiator: false,
   
     
     
    trickle: false,
   
     
     
    });
   
     
     
   
 peer.on("signal", signal => {
   
     
     
    socketRef.current.emit("returning signal", { signal, callerID });
   
     
     
    });
   
     
     
   
 peer.on("data", handleReceivingData);
   
     
     
   
 peer.signal(incomingSignal);
   
     
     
    setConnection(true);
   
     
     
    return peer;
   
     
     
    }
   
     
     
   
 function handleReceivingData(data) {
   
     
     
    if (data.toString().includes("done")) {
   
     
     
    setGotFile(true);
   
     
     
    const parsed = JSON.parse(data);
   
     
     
    fileNameRef.current = parsed.fileName;
   
     
     
    } else {
   
     
     
    worker.postMessage(data);
   
     
     
    }
   
     
     
    }
   
     
     
   
 function download() {
   
     
     
    setGotFile(false);
   
     
     
    worker.postMessage("download");
   
     
     
    worker.addEventListener("message", event => {
   
     
     
    const stream = event.data.stream();
   
     
     
    const fileStream = streamSaver.createWriteStream(fileNameRef.current);
   
     
     
    stream.pipeTo(fileStream);
   
     
     
    })
   
     
     
    }
   
     
     
   
 function selectFile(e) {
   
     
     
    setFile(e.target.files[0]);
   
     
     
    }
   
     
     
   
 function sendFile() {
   
     
     
    const peer = peerRef.current;
   
     
     
    const stream = file.stream();
   
     
     
    const reader = stream.getReader();
   
     
     
   
 reader.read().then(obj => {
   
     
     
    handlereading(obj.done, obj.value);
   
     
     
    });
   
     
     
   
 function handlereading(done, value) {
   
     
     
    if (done) {
   
     
     
    peer.write(JSON.stringify({ done: true, fileName: file.name }));
   
     
     
    return;
   
     
     
    }
   
     
     
   
 peer.write(value);
   
     
     
    reader.read().then(obj => {
   
     
     
    handlereading(obj.done, obj.value);
   
     
     
    })
   
     
     
    }
   
     
     
   
 }
   
     
     
   
 let body;
   
     
     
    if (connectionEstablished) {
   
     
     
    body = (
   
     
     
    <div>
   
     
     
    <input onChange={selectFile} type="file" />
   
     
     
    <button onClick={sendFile}>Send file</button>
   
     
     
    </div>
   
     
     
    );
   
     
     
    } else {
   
     
     
    body = (
   
     
     
    <h1>Once you have a peer connection, you will be able to share files</h1>
   
     
     
    );
   
     
     
    }
   
     
     
   
 let downloadPrompt;
   
     
     
    if (gotFile) {
   
     
     
    downloadPrompt = (
   
     
     
    <div>
   
     
     
    <span>You have received a file. Would you like to download the file?</span>
   
     
     
    <button onClick={download}>Yes</button>
   
     
     
    </div>
   
     
     
    );
   
     
     
    }
   
     
     
   
 return (
   
     
     
    <Container>
   
     
     
    {body}
   
     
     
    {downloadPrompt}
   
     
     
    </Container>
   
     
     
    );
   
     
     
   };
   
     
     
   
export default Room;
  
    
    
    
  
    
    
  
   
     
     
   let array = [];
   
     
     
   self.addEventListener("message", event => {
   
     
     
    if (event.data === "download") {
   
     
     
    const blob = new Blob(array);
   
     
     
    self.postMessage(blob);
   
     
     
    array = [];
   
     
     
    } else if (event.data === "abort") {
   
     
     
    array = [];
   
     
     
    } else {
   
     
     
    array.push(event.data);
   
     
     
    }
   
     
     
   })
  
    
    
    
- 支持几乎所有的浏览器 
- 支持庞大的文档大小——正如前面提到的,这是我们为什么要实现它的基本解释。 
- 一个更好的方法来破译所发送信息的度量——通过在缓冲区中发送一个记录,我们现在可以显示信息,例如,发送的文档的级别,发送记录的速度等等。 
- 识别未完成发送的文件——在无法完全发送文件的情况下,现在能够以不同的方式获取和处理文件。 
- 信令服务器(STUN和TURN服务器)。 
- 使多个对等连接可拓展。 
- 当WebRTC不能工作时才用的一种混合共享方式。 
- 提高传输效率和速度。 
点击【阅读原文】了解更多详细信息
