<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      打造高效 P2P 文件傳輸與桌面共享工具:基于 WebRTC、Go 和 React

      ?? 經(jīng)過(guò)數(shù)月的開(kāi)發(fā),我的個(gè)人項(xiàng)目 File-Transfer-Go 終于實(shí)現(xiàn)了一個(gè)小目標(biāo):支持文件傳輸桌面共享文本同步!無(wú)需復(fù)雜配置,打開(kāi)網(wǎng)頁(yè)即開(kāi)即用使用,數(shù)據(jù)傳輸全程 P2P,安全又高效!

      項(xiàng)目地址: GitHub - MatrixSeven/file-transfer-go
      體驗(yàn)地址: File Transfer - 文件傳輸

      1. 項(xiàng)目背景與初心

      作為一個(gè)經(jīng)常需要向 Windows 服務(wù)器傳輸文件的開(kāi)發(fā)者,我對(duì)傳統(tǒng)網(wǎng)盤(pán)的繁瑣流程(登錄、下載客戶(hù)端)感到厭倦。同時(shí),我對(duì) WebRTC 的 P2P 技術(shù)充滿(mǎn)興趣,想借此機(jī)會(huì)深入學(xué)習(xí)并打造一個(gè)即開(kāi)即用的工具,集文件傳輸、桌面共享和文本同步于一體。目標(biāo)是:直觀、簡(jiǎn)潔、高效,符合高頻使用場(chǎng)景。

      2. 技術(shù)架構(gòu)

      項(xiàng)目采用前后端分離架構(gòu),所有數(shù)據(jù)傳輸基于 WebRTC 實(shí)現(xiàn) P2P 連接,服務(wù)器僅用于信令交換,保障隱私和安全:

      • 后端:基于 Go 開(kāi)發(fā)的輕量信令服務(wù)器,負(fù)責(zé) WebRTC 的 ICE 候選交換和會(huì)話(huà)協(xié)商。
      • 前端:使用 ReactNext.js,提供流暢的交互界面和狀態(tài)管理。
      • 核心技術(shù):WebRTC 實(shí)現(xiàn) P2P 數(shù)據(jù)通道,涵蓋文件傳輸、桌面共享和文本同步。
      • 隱私設(shè)計(jì):服務(wù)器不存儲(chǔ)任何設(shè)備信息或傳輸數(shù)據(jù),連接通過(guò)取件碼手動(dòng)匹配。

      3. 核心功能與實(shí)現(xiàn)

      3.1 p2p打洞

      基于webrtc進(jìn)行網(wǎng)絡(luò)打洞和穿透
      image

      3.2 文件傳輸

      通過(guò) WebRTC 的 useSharedWebRTCManageruseFileTransferBusiness 實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)文件傳輸,支持大文件分片和傳輸。以下是核心代碼示例:

        // 安全發(fā)送單個(gè)文件塊
        const sendChunkWithAck = useCallback(async (
          fileId: string,
          chunkIndex: number,
          chunkData: ArrayBuffer,
          checksum: string,
          retryCount = 0
        ): Promise<boolean> => {
          return new Promise((resolve) => {
            const chunkKey = `${fileId}-${chunkIndex}`;
            
            // 設(shè)置確認(rèn)回調(diào)
            const ackCallback = (ack: ChunkAck) => {
              if (ack.success) {
                resolve(true);
              } else {
                console.warn(`文件塊 ${chunkIndex} 確認(rèn)失敗,準(zhǔn)備重試`);
                resolve(false);
              }
            };
      
            // 注冊(cè)確認(rèn)回調(diào)
            if (!chunkAckCallbacks.current.has(chunkKey)) {
              chunkAckCallbacks.current.set(chunkKey, new Set());
            }
            chunkAckCallbacks.current.get(chunkKey)!.add(ackCallback);
      
            // 設(shè)置超時(shí)定時(shí)器
            const timeout = setTimeout(() => {
              console.warn(`文件塊 ${chunkIndex} 確認(rèn)超時(shí)`);
              chunkAckCallbacks.current.get(chunkKey)?.delete(ackCallback);
              resolve(false);
            }, ACK_TIMEOUT);
      
            pendingChunks.current.set(chunkKey, timeout);
      
            // 發(fā)送塊信息
            connection.sendMessage({
              type: 'file-chunk-info',
              payload: {
                fileId,
                chunkIndex,
                totalChunks: 0, // 這里不需要,因?yàn)橐呀?jīng)在元數(shù)據(jù)中發(fā)送
                checksum
              }
            }, CHANNEL_NAME);
      
            // 發(fā)送塊數(shù)據(jù)
            connection.sendData(chunkData);
          });
        }, [connection]);
      

      然后通過(guò)webrtc的數(shù)據(jù)通道進(jìn)行發(fā)送

      
        // 發(fā)送二進(jìn)制數(shù)據(jù)
        const sendData = useCallback((data: ArrayBuffer) => {
          const dataChannel = dcRef.current;
          if (!dataChannel || dataChannel.readyState !== 'open') {
            console.error('[SharedWebRTC] 數(shù)據(jù)通道未準(zhǔn)備就緒');
            return false;
          }
      
          try {
            dataChannel.send(data);
            console.log('[SharedWebRTC] 發(fā)送數(shù)據(jù):', data.byteLength, 'bytes');
            return true;
          } catch (error) {
            console.error('[SharedWebRTC] 發(fā)送數(shù)據(jù)失敗:', error);
            return false;
          }
        }, []);
      

      3.3 桌面共享

      通過(guò)webrtcAPI拿到 MediaStream 然后進(jìn)行傳輸

        // 添加媒體軌道
        const addTrack = useCallback((track: MediaStreamTrack, stream: MediaStream) => {
          const pc = pcRef.current;
          if (!pc) {
            console.error('[SharedWebRTC] PeerConnection 不可用');
            return null;
          }
          
          try {
            return pc.addTrack(track, stream);
          } catch (error) {
            console.error('[SharedWebRTC] 添加軌道失敗:', error);
            return null;
          }
        }, []);
      

      接收方

      
        // 設(shè)置視頻流
        useEffect(() => {
          if (videoRef.current && stream) {
            console.log('[DesktopViewer] ?? 設(shè)置視頻流,軌道數(shù)量:', stream.getTracks().length);
            stream.getTracks().forEach(track => {
              console.log('[DesktopViewer] 軌道詳情:', track.kind, track.id, track.enabled, track.readyState);
            });
            
            videoRef.current.srcObject = stream;
            console.log('[DesktopViewer] ? 視頻元素已設(shè)置流');
            
            // 重置狀態(tài)
            hasAttemptedAutoplayRef.current = false;
            setNeedsUserInteraction(false);
            setIsPlaying(false);
            
            // 添加事件監(jiān)聽(tīng)器來(lái)調(diào)試視頻加載
            const video = videoRef.current;
            const handleLoadStart = () => console.log('[DesktopViewer] ?? 視頻開(kāi)始加載');
            const handleLoadedMetadata = () => {
              console.log('[DesktopViewer] ?? 視頻元數(shù)據(jù)已加載');
              console.log('[DesktopViewer] ?? 視頻尺寸:', video.videoWidth, 'x', video.videoHeight);
            };
            const handleCanPlay = () => {
              console.log('[DesktopViewer] ?? 視頻可以開(kāi)始播放');
              // 只在還未嘗試過(guò)自動(dòng)播放時(shí)才嘗試
              if (!hasAttemptedAutoplayRef.current) {
                hasAttemptedAutoplayRef.current = true;
                video.play()
                  .then(() => {
                    console.log('[DesktopViewer] ? 視頻自動(dòng)播放成功');
                    setIsPlaying(true);
                    setNeedsUserInteraction(false);
                  })
                  .catch(e => {
                    console.log('[DesktopViewer] ?? 自動(dòng)播放被阻止,需要用戶(hù)交互:', e.message);
                    setIsPlaying(false);
                    setNeedsUserInteraction(true);
                  });
              }
            };
            const handlePlay = () => {
              console.log('[DesktopViewer] ?? 視頻開(kāi)始播放');
              setIsPlaying(true);
              setNeedsUserInteraction(false);
            };
            const handlePause = () => {
              console.log('[DesktopViewer] ?? 視頻暫停');
              setIsPlaying(false);
            };
            const handleError = (e: Event) => console.error('[DesktopViewer] ?? 視頻播放錯(cuò)誤:', e);
            
            video.addEventListener('loadstart', handleLoadStart);
            video.addEventListener('loadedmetadata', handleLoadedMetadata);
            video.addEventListener('canplay', handleCanPlay);
            video.addEventListener('play', handlePlay);
            video.addEventListener('pause', handlePause);
            video.addEventListener('error', handleError);
            
            return () => {
              video.removeEventListener('loadstart', handleLoadStart);
              video.removeEventListener('loadedmetadata', handleLoadedMetadata);
              video.removeEventListener('canplay', handleCanPlay);
              video.removeEventListener('play', handlePlay);
              video.removeEventListener('pause', handlePause);
              video.removeEventListener('error', handleError);
            };
          } else if (videoRef.current && !stream) {
            console.log('[DesktopViewer] ? 清除視頻流');
            videoRef.current.srcObject = null;
            setIsPlaying(false);
            setNeedsUserInteraction(false);
            hasAttemptedAutoplayRef.current = false;
          }
        }, [stream]);
      

      image

      posted @ 2025-08-27 15:18  菜狗_無(wú)知  閱讀(1076)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 久热色视频精品在线观看| 国产国产久热这里只有精品| 少妇av一区二区三区无码| 国产精品无码一区二区三区电影| 久久久久高潮毛片免费全部播放 | 亚洲av不卡电影在线网址最新| 亚洲sm另类一区二区三区| 国产综合色精品一区二区三区 | 免费的特黄特色大片| 国产激情一区二区三区午夜| 亚洲欧洲无码av电影在线观看| 国产乱码精品一区二三区| 白朗县| 精品国产成人国产在线视| 中文字幕av日韩有码| 人妻日韩精品中文字幕| 午夜福利日本一区二区无码| 亚洲中文字幕第一页在线| 午夜男女爽爽影院在线| www国产无套内射com| 午夜福利国产一区二区三区| 国产精品中文av专线| 中文字幕国产精品资源| 伊人成人在线视频免费| 99久9在线视频 | 传媒| 久久婷婷五月综合色和啪| 欧美亚洲一区二区三区在线| 国产精品毛片在线完整版| 国产另类ts人妖一区二区| 天天爽夜夜爱| 亚洲中文字幕精品一区二区三区 | av一本久道久久综合久久鬼色 | 中文字幕一区二区三区久久蜜桃 | 共和县| 国产黄色一区二区三区四区| 日韩在线视频一区二区三| 亚洲综合久久精品哦夜夜嗨| 久久精品国产亚洲AⅤ无码| 欧美丰满熟妇xxxx性ppx人交| 国产一级精品在线免费看| 日日摸天天爽天天爽视频|