首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

海康威視監控 Web 檢視系統 (二):中轉伺服器 Socket 服務與多客戶端分發架構

     編輯:關於.NET

架構回顧

海康設備單機限 6 客戶端。方案:中轉伺服器 單一連線取流 → 內存緩存 → Socket 分發給多個 Web ActiveX 客戶端。

SDK 標準流程簡化

NET_DVR_Init()                           // 初始化 SDK
NET_DVR_Login_V30(ip, port, user, pwd)   // 登入設備
NET_DVR_RealPlay_V30(..., RealDataCallBack) // 開始預覽,註冊回調
// RealDataCallBack 中接收視訊資料

伺服器端三大類別設計

1. Server:SDK 取流 + Socket 監聽

class Server
{
    int _userId = -1;
    byte[] _headStream; // 40 bytes 頭部
    ClientList _clients = ClientList.Instance;
    Socket _listenSocket;
    Semaphore _maxClients;

    public Server(IPEndPoint localEp, int maxClients, int channel)
    {
        if (!InitSdk()) return;
        StartRealPlay(channel);
        _listenSocket = new Socket(localEp.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        _listenSocket.Bind(localEp);
        _maxClients = new Semaphore(maxClients, maxClients);
        _listenSocket.Listen(100);
        BeginAccept(null);
    }

    bool InitSdk()
    {
        if (!CHCNetSDK.NET_DVR_Init()) return false;
        var info = new CHCNetSDK.NET_DVR_DEVICEINFO_V30();
        _userId = CHCNetSDK.NET_DVR_Login_V30("DEV_IP", 8000, "admin", "pwd", ref info);
        return _userId != -1;
    }

    void StartRealPlay(int channel)
    {
        var clientInfo = new CHCNetSDK.NET_DVR_CLIENTINFO { lChannel = channel, lLinkMode = 0 };
        var cb = new CHCNetSDK.REALDATACALLBACK(RealDataCallback);
        CHCNetSDK.NET_DVR_RealPlay_V30(_userId, ref clientInfo, cb, IntPtr.Zero, 1);
    }

    void RealDataCallback(int handle, uint dataType, IntPtr buf, uint size, IntPtr user)
    {
        byte[] data = new byte[size];
        Marshal.Copy(buf, data, 0, (int)size);
        if (dataType == CHCNetSDK.NET_DVR_SYSHEAD) _headStream = data; // 保存 40 bytes
        _clients.Broadcast(data); // 分發給所有客戶端
    }

    // Socket Async Accept 實作...
}

2. ClientList:單例客戶端管理

class ClientList
{
    static ClientList _instance;
    List<Client> _clients = new List<Client>();
    public static ClientList Instance { get { if (_instance==null) _instance=new ClientList(); return _instance; } }

    public void AddClient(Client c) { _clients.Add(c); }

    public void Broadcast(byte[] data)
    {
        // 移除斷開連線的客戶端
        _clients.RemoveAll(c => c.Error != SocketError.Success);
        // CPU 保護:使用率 > 50% 時微延遲
        var cpu = new PerformanceCounter("Processor", "% Processor Time", "_Total");
        foreach (var c in _clients)
        {
            c.Send(data);
            if (cpu.NextValue() > 50) Thread.Sleep(10);
        }
    }
}

3. Client:單客戶端專用發送執行緒

class Client
{
    Socket _socket;
    byte[] _headStream;
    ManualResetEvent _sendSignal = new ManualResetEvent(false);
    byte[] _pendingData;
    Thread _sendThread;
    SocketError _error = SocketError.Success;

    public Client(Socket socket, byte[] headStream)
    {
        _socket = socket; _headStream = headStream;
        _sendThread = new Thread(() => {
            while (true)
            {
                _sendSignal.WaitOne();
                if (_error == SocketError.Success)
                {
                    try { _socket.Send(_pendingData); }
                    catch { Destroy(); break; }
                }
                _sendSignal.Reset();
            }
        }) { IsBackground = true };
        _sendThread.Start();
    }

    public void Send(byte[] data)
    {
        if (_error != SocketError.Success) return;
        // 首次發送頭部 40 bytes,之後發送資料幀
        _pendingData = (_pendingData == null && _headStream.Length == 40) ? _headStream : data;
        _sendSignal.Set();
    }

    void Destroy() { /* 關閉 Socket、結束執行緒、標記錯誤 */ }
    public SocketError Error { get { return _error; } }
}

關鍵設計決策

決策理由
Client 專用發送執行緒而非 ThreadPool持續高頻發送,避免執行緒池耗盡、排隊延遲。
ManualResetEvent 控制發送順序確保幀序嚴格遞增,防止亂序導致解碼錯誤/跳幀。
Server 獨立保存 Head 40 bytes每個新客戶端連線必須先收到 Head 才能初始化解碼器。
PerformanceCounter 限流防止 CPU 100% 導致取流延遲、丟幀。

下一步

第三篇將實作 Web ActiveX 播放器,接收中轉伺服器資料並解碼顯示。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved