You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Onvif摄像头告警接收异常:Socket阻塞与数据堆积问题排查

Hey there! Let's dive into your ONVIF camera alert reception issues—you've got three implementations with very different behaviors, so we'll break each down to find the root causes and fixes.

First, a quick recap of your setup: You have an ONVIF camera sending XML motion alerts to your server's 8085 port. Your Go HTTP server works flawlessly, but your C++ raw socket and C# programs are hitting frustrating snags. Let's tackle each problem one by one:

1. C++ Raw Socket Stuck on accept(), Gets Old Packets After Restart

Root Cause Guess

ONVIF event notifications typically use SOAP over HTTP (TCP-based), so your camera is likely establishing a TCP connection to send alerts. Here's what's probably going wrong:

  • If your C++ program is single-threaded, after calling accept() to grab a client connection, it might get stuck blocking on read() (waiting for more data that never arrives, or failing to handle partial reads correctly). This means the program never loops back to accept() to handle new connections from the camera.
  • The camera probably caches unsent alerts when its send buffer fills up (since your program isn't pulling data from the connection). When you restart the program, the old TCP connection drops, the camera re-establishes a new connection, and dumps all cached alerts at once.
  • Alternatively, you might not be setting the SO_REUSEADDR socket option, so after a restart, the old connection is stuck in TIME_WAIT state and blocks your new listener from binding to 8085 immediately.
  • Another angle: You're not closing client sockets properly after the camera disconnects, leading to file descriptor leaks that eventually prevent new accept() calls.

Fixes

  • Use multi-threading or IO multiplexing: If you're using a single thread, switch to spawning a new thread for each accepted connection, or use select(), poll(), or epoll() (on Linux) to handle multiple connections without blocking on a single read().
  • Set read timeouts: Use setsockopt() with SO_RCVTIMEO to avoid infinite blocking on read(). If no data comes in after a reasonable timeout, close the client socket and return to accept().
  • Properly close client sockets: Whenever the camera disconnects (detected via read() returning 0 bytes), call close() on the client socket to free up resources.
  • Enable SO_REUSEADDR: When creating your listening socket, set this option to avoid TIME_WAIT issues after restarts. Example snippet:
    int opt = 1;
    if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    
2. C#: Receive() Doesn't Clear Buffer, Data Piles Up, Port Gets Clogged, AcceptSocket() Blocks

Root Cause Guess

C#'s Socket.Receive() only reads as much data as fits in your buffer—it doesn't guarantee to grab the entire HTTP/SOAP message in one call. If you're not looping to read all available data, leftover bytes stay in the TCP receive buffer. Over time:

  • The camera's send buffer fills up, so it stops sending new alerts.
  • If you're not closing connections properly, you end up with dozens (or hundreds) of stale connections in TIME_WAIT or ESTABLISHED state, exhausting available ports and causing AcceptSocket() to block indefinitely because no new connections can be established.

Fixes

  • Read until you get the full message: ONVIF alerts are HTTP POST requests, so parse the Content-Length header first, then loop Receive() until you've read exactly that many bytes. Alternatively, read until you hit the HTTP message boundary (\r\n\r\n followed by the body).
  • Use TcpListener and NetworkStream instead of raw Socket: These higher-level abstractions handle stream reading more gracefully. Example:
    TcpListener listener = new TcpListener(IPAddress.Any, 8085);
    listener.Start();
    while (true) {
        using TcpClient client = listener.AcceptTcpClient();
        using NetworkStream stream = client.GetStream();
        // Read the full HTTP request from the stream
        byte[] buffer = new byte[4096];
        int bytesRead;
        StringBuilder requestBuilder = new StringBuilder();
        while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) {
            requestBuilder.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead));
            // Check if we've reached the end of the HTTP message
            if (requestBuilder.ToString().Contains("\r\n\r\n")) {
                // Parse the request and extract UtcTime
                break;
            }
        }
    }
    
  • Close connections properly: Always wrap TcpClient/Socket in using statements (or explicitly call Close()) to ensure connections are closed and resources are freed.
  • Adjust socket linger settings: If you're seeing too many TIME_WAIT connections, set Socket.LingerState to reduce the wait time, or enable SocketOptionName.ReuseAddress on your listener.
Why Does the Go HTTP Server Work?

Go's standard HTTP server handles all the heavy lifting for you: it uses goroutines to handle each connection concurrently, automatically reads full HTTP requests, manages connection timeouts, and cleans up stale connections. You don't have to manually handle the low-level socket details that trip up C++ and C# implementations.

If you can share snippets of your C++ and C# code, we can pinpoint the exact issues even more accurately!

内容的提问来源于stack exchange,提问作者hamidi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 08:52:35