wenhongquan пре 1 дан
родитељ
комит
529753e188
5 измењених фајлова са 408 додато и 7 уклоњено
  1. 11 2
      docker-compose.yml
  2. 171 0
      docker-network-test.sh
  3. 26 3
      docker-start.sh
  4. 173 0
      network-test.sh
  5. 27 2
      src/rtsp_client.cpp

+ 11 - 2
docker-compose.yml

@@ -8,8 +8,8 @@ services:
     platform: linux/amd64
     image: k8s.device.wenhq.top:8583/docker_r/jtjai_media:latest
     container_name: jtjai_media
-    ports:
-      - "8080:8080"
+    # 使用host网络模式以解决RTSP连接问题
+    network_mode: host
     volumes:
       # 挂载配置文件(可选,如果需要修改配置)
       - ./config.json:/app/config.json:ro
@@ -18,6 +18,15 @@ services:
     restart: unless-stopped
     environment:
       - TZ=Asia/Shanghai
+      # 添加网络调试环境变量
+      - RTSP_DEBUG=1
+    # 添加额外的网络配置
+    extra_hosts:
+      - "host.docker.internal:host-gateway"
+    # DNS配置
+    dns:
+      - 8.8.8.8
+      - 114.114.114.114
     # 资源限制(可选)
     deploy:
       resources:

+ 171 - 0
docker-network-test.sh

@@ -0,0 +1,171 @@
+#!/bin/bash
+
+# Docker容器内RTSP连接测试脚本
+
+set -e
+
+# 颜色定义
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m'
+
+print_info() {
+    echo -e "${GREEN}[INFO]${NC} $1"
+}
+
+print_warn() {
+    echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+print_error() {
+    echo -e "${RED}[ERROR]${NC} $1"
+}
+
+# 在Docker容器内测试RTSP连接
+test_rtsp_in_docker() {
+    print_info "=========================================="
+    print_info "Docker容器内RTSP连接测试"
+    print_info "=========================================="
+    
+    # 确保容器正在运行
+    if ! docker ps | grep -q jtjai_media; then
+        print_error "jtjai_media容器未运行,请先启动容器"
+        return 1
+    fi
+    
+    print_info "容器状态: ✅ 运行中"
+    
+    # 在容器内执行网络诊断
+    print_info "容器内网络环境:"
+    docker exec jtjai_media bash -c "
+        echo '=== 网络配置 ==='
+        ip addr show | grep inet
+        echo ''
+        echo '=== DNS配置 ==='
+        cat /etc/resolv.conf
+        echo ''
+        echo '=== 路由表 ==='
+        ip route show
+        echo ''
+    "
+    
+    # 测试从容器内访问RTSP URLs
+    print_info "测试容器内RTSP连接..."
+    
+    # 读取配置文件中的RTSP URLs
+    local urls=($(grep -o '"rtsp://[^"]*"' config.json | sed 's/"//g'))
+    
+    for url in "${urls[@]}"; do
+        print_info "测试RTSP URL: $url"
+        
+        # 解析主机和端口
+        local host=$(echo $url | sed -n 's|rtsp://\([^:]*\):\([0-9]*\)/.*|\1|p')
+        local port=$(echo $url | sed -n 's|rtsp://\([^:]*\):\([0-9]*\)/.*|\2|p')
+        
+        if [[ -n "$host" && -n "$port" ]]; then
+            print_info "目标: $host:$port"
+            
+            # 在容器内测试连接
+            if docker exec jtjai_media timeout 10 nc -z $host $port 2>/dev/null; then
+                print_info "✅ 容器内端口连接成功"
+            else
+                print_error "❌ 容器内端口连接失败"
+            fi
+            
+            # 测试DNS解析
+            if docker exec jtjai_media nslookup $host > /dev/null 2>&1; then
+                print_info "✅ 容器内DNS解析成功"
+            else
+                print_error "❌ 容器内DNS解析失败"
+            fi
+        else
+            print_error "无法解析RTSP URL格式: $url"
+        fi
+        echo ""
+    done
+}
+
+# 比较宿主机和容器的网络差异
+compare_network() {
+    print_info "=========================================="
+    print_info "宿主机vs容器网络对比"
+    print_info "=========================================="
+    
+    echo "🖥️  宿主机网络信息:"
+    echo "  外网IP: $(timeout 5 curl -s ifconfig.me || echo '获取失败')"
+    echo "  DNS: $(cat /etc/resolv.conf | grep nameserver | head -1 | awk '{print $2}')"
+    echo "  网关: $(ip route | grep default | awk '{print $3}')"
+    echo ""
+    
+    if docker ps | grep -q jtjai_media; then
+        echo "🐳 容器网络信息:"
+        docker exec jtjai_media bash -c "
+            echo '  容器IP: '$(ip addr show eth0 2>/dev/null | grep 'inet ' | awk '{print $2}' || echo 'host模式')
+            echo '  DNS: '$(cat /etc/resolv.conf | grep nameserver | head -1 | awk '{print $2}')
+            echo '  网关: '$(ip route | grep default | awk '{print $3}' || echo 'host模式')
+        " 2>/dev/null || echo "  网络模式: host模式"
+    else
+        print_warn "容器未运行,无法获取容器网络信息"
+    fi
+    echo ""
+}
+
+# 提供解决方案建议
+provide_solutions() {
+    print_info "=========================================="
+    print_info "常见解决方案"
+    print_info "=========================================="
+    
+    echo "如果遇到连接问题,可以尝试以下方案:"
+    echo ""
+    echo "1. 🌐 使用host网络模式 (推荐)"
+    echo "   - 修改docker-compose.yml添加: network_mode: host"
+    echo "   - 或使用: docker run --network host"
+    echo ""
+    echo "2. 🔧 调整超时设置"
+    echo "   - 增加config.json中的connection_timeout_seconds"
+    echo "   - 增加read_timeout_seconds"
+    echo ""
+    echo "3. 🛠️  检查防火墙设置"
+    echo "   - 确保RTSP端口(通常554或自定义端口)未被阻止"
+    echo "   - 检查iptables规则"
+    echo ""
+    echo "4. 🌍 DNS配置"
+    echo "   - 在docker-compose.yml中添加public DNS:"
+    echo "     dns:"
+    echo "       - 8.8.8.8"
+    echo "       - 114.114.114.114"
+    echo ""
+    echo "5. 📡 网络驱动"
+    echo "   - 如果使用bridge网络,考虑切换到host模式"
+    echo "   - 或创建自定义网络"
+    echo ""
+}
+
+# 主函数
+main() {
+    echo ""
+    print_info "Docker RTSP连接诊断工具"
+    echo ""
+    
+    # 检查Docker是否安装
+    if ! command -v docker &> /dev/null; then
+        print_error "Docker未安装"
+        exit 1
+    fi
+    
+    # 比较网络环境
+    compare_network
+    
+    # 测试容器内连接
+    test_rtsp_in_docker
+    
+    # 提供解决方案
+    provide_solutions
+    
+    print_info "诊断完成!"
+}
+
+# 执行主函数
+main

+ 26 - 3
docker-start.sh

@@ -81,14 +81,18 @@ start_with_docker() {
     print_info "构建Docker镜像..."
     docker build --build-arg BUILDPLATFORM=linux/amd64 --build-arg TARGETPLATFORM=linux/amd64 -t jtjai_media:latest .
     
-    # 运行容器
-    print_info "启动Docker容器..."
+    # 运行容器(使用host网络模式解决RTSP连接问题)
+    print_info "启动Docker容器(使用host网络模式)..."
     docker run -d \
         --name jtjai_media \
         --platform linux/amd64 \
-        -p 8080:8080 \
+        --network host \
         -v "$(pwd)/output:/app/output" \
         -v "$(pwd)/config.json:/app/config.json:ro" \
+        -e TZ=Asia/Shanghai \
+        -e RTSP_DEBUG=1 \
+        --dns 8.8.8.8 \
+        --dns 114.114.114.114 \
         --restart unless-stopped \
         jtjai_media:latest
     
@@ -134,6 +138,25 @@ main() {
     print_info "=========================================="
     echo ""
     
+    # 询问是否先进行网络测试
+    read -p "是否先进行RTSP网络连通性测试? (y/n) " -n 1 -r
+    echo ""
+    if [[ $REPLY =~ ^[Yy]$ ]]; then
+        print_info "开始网络连通性测试..."
+        if [[ -x "./network-test.sh" ]]; then
+            ./network-test.sh
+        else
+            print_warn "网络测试脚本不存在或不可执行"
+        fi
+        echo ""
+        read -p "网络测试完成,是否继续启动Docker服务? (y/n) " -n 1 -r
+        echo ""
+        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+            print_info "用户取消启动"
+            exit 0
+        fi
+    fi
+    
     # 检查Docker
     check_docker
     

+ 173 - 0
network-test.sh

@@ -0,0 +1,173 @@
+#!/bin/bash
+
+# RTSP网络连接诊断脚本
+
+set -e
+
+# 颜色定义
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+print_info() {
+    echo -e "${GREEN}[INFO]${NC} $1"
+}
+
+print_warn() {
+    echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+print_error() {
+    echo -e "${RED}[ERROR]${NC} $1"
+}
+
+# 从配置文件读取RTSP URLs
+get_rtsp_urls() {
+    if [[ -f "config.json" ]]; then
+        # 使用jq解析JSON(如果可用)
+        if command -v jq &> /dev/null; then
+            jq -r '.streams[].rtsp_url' config.json
+        else
+            # 简单的grep解析
+            grep -o '"rtsp://[^"]*"' config.json | sed 's/"//g'
+        fi
+    else
+        print_error "配置文件 config.json 不存在"
+        exit 1
+    fi
+}
+
+# 测试网络连通性
+test_network_connectivity() {
+    local url=$1
+    print_info "测试RTSP URL: $url"
+    
+    # 解析URL获取主机和端口
+    local host=$(echo $url | sed -n 's|rtsp://\([^:]*\):\([0-9]*\)/.*|\1|p')
+    local port=$(echo $url | sed -n 's|rtsp://\([^:]*\):\([0-9]*\)/.*|\2|p')
+    
+    if [[ -z "$host" || -z "$port" ]]; then
+        print_error "无法解析RTSP URL: $url"
+        return 1
+    fi
+    
+    print_info "主机: $host, 端口: $port"
+    
+    # DNS解析测试
+    print_info "测试DNS解析..."
+    if nslookup $host > /dev/null 2>&1; then
+        print_info "✅ DNS解析成功"
+        local ip=$(nslookup $host | grep "Address:" | tail -1 | awk '{print $2}')
+        print_info "解析IP: $ip"
+    else
+        print_error "❌ DNS解析失败"
+        return 1
+    fi
+    
+    # 端口连通性测试
+    print_info "测试端口连通性..."
+    if timeout 10 nc -z $host $port 2>/dev/null; then
+        print_info "✅ 端口 $port 可达"
+    else
+        print_error "❌ 端口 $port 不可达"
+        return 1
+    fi
+    
+    # RTSP协议测试
+    print_info "测试RTSP协议响应..."
+    if timeout 10 nc -z $host $port 2>/dev/null; then
+        # 发送RTSP OPTIONS请求
+        local rtsp_response=$(timeout 5 bash -c "echo -e 'OPTIONS $url RTSP/1.0\r\nCSeq: 1\r\nUser-Agent: Network-Test\r\n\r\n' | nc $host $port 2>/dev/null" || echo "")
+        
+        if [[ "$rtsp_response" == *"RTSP/1.0"* ]]; then
+            print_info "✅ RTSP服务器响应正常"
+            return 0
+        else
+            print_warn "⚠️  端口可达但RTSP服务可能异常"
+            return 1
+        fi
+    else
+        print_error "❌ 无法连接到RTSP服务器"
+        return 1
+    fi
+}
+
+# 主函数
+main() {
+    echo ""
+    print_info "=========================================="
+    print_info "RTSP网络连接诊断工具"
+    print_info "=========================================="
+    echo ""
+    
+    # 检查必要工具
+    for tool in nc nslookup timeout; do
+        if ! command -v $tool &> /dev/null; then
+            print_error "缺少必要工具: $tool"
+            print_info "请安装: apt-get install netcat-openbsd dnsutils coreutils"
+            exit 1
+        fi
+    done
+    
+    # 显示网络环境信息
+    print_info "网络环境信息:"
+    echo "  主机名: $(hostname)"
+    echo "  网络接口: $(ip route get 8.8.8.8 | awk '{print $5; exit}')"
+    echo "  外网IP检测: $(timeout 5 curl -s ifconfig.me || echo "无法获取")"
+    echo "  DNS配置:"
+    cat /etc/resolv.conf | grep nameserver | head -3 | sed 's/^/    /'
+    echo ""
+    
+    # 获取RTSP URLs
+    print_info "从配置文件读取RTSP流地址..."
+    local urls=($(get_rtsp_urls))
+    
+    if [[ ${#urls[@]} -eq 0 ]]; then
+        print_error "配置文件中未找到RTSP URL"
+        exit 1
+    fi
+    
+    print_info "找到 ${#urls[@]} 个RTSP流地址"
+    echo ""
+    
+    # 测试每个URL
+    local success_count=0
+    local total_count=${#urls[@]}
+    
+    for url in "${urls[@]}"; do
+        print_info "========== 测试流 $((success_count + 1))/$total_count =========="
+        if test_network_connectivity "$url"; then
+            ((success_count++))
+            print_info "✅ 测试通过"
+        else
+            print_error "❌ 测试失败"
+        fi
+        echo ""
+    done
+    
+    # 显示总结
+    print_info "=========================================="
+    print_info "测试完成"
+    print_info "=========================================="
+    print_info "成功: $success_count/$total_count"
+    
+    if [[ $success_count -eq $total_count ]]; then
+        print_info "🎉 所有RTSP流连接测试通过!"
+        print_info "如果Docker中仍无法连接,请检查:"
+        print_info "  1. Docker网络模式是否为host"
+        print_info "  2. 容器内DNS配置是否正确"
+        print_info "  3. 防火墙设置是否阻止连接"
+    else
+        print_warn "⚠️  部分RTSP流连接失败"
+        print_info "建议检查:"
+        print_info "  1. 网络连接状态"
+        print_info "  2. RTSP服务器状态" 
+        print_info "  3. 防火墙配置"
+    fi
+    
+    echo ""
+}
+
+# 执行主函数
+main

+ 27 - 2
src/rtsp_client.cpp

@@ -123,6 +123,21 @@ RTSPClientStats RTSPClient::get_stats() const {
 }
 
 bool RTSPClient::initialize_input() {
+    // 网络诊断信息
+    std::cout << "=== 网络诊断信息 ===" << std::endl;
+    std::cout << "RTSP URL: " << config_.rtsp_url << std::endl;
+    
+    // 检查是否在Docker环境中运行
+    const char* rtsp_debug = std::getenv("RTSP_DEBUG");
+    bool debug_mode = (rtsp_debug != nullptr && std::string(rtsp_debug) == "1");
+    
+    if (debug_mode) {
+        std::cout << "Docker调试模式已启用" << std::endl;
+        // 显示网络环境信息
+        system("echo 'DNS配置:' && cat /etc/resolv.conf");
+        system("echo '网络接口:' && ip route show");
+    }
+    
     // 分配输入格式上下文
     input_format_ctx_ = avformat_alloc_context();
     if (!input_format_ctx_) {
@@ -136,11 +151,21 @@ bool RTSPClient::initialize_input() {
     // 设置RTSP选项(Docker环境优化)
     AVDictionary* options = nullptr;
     av_dict_set(&options, "rtsp_transport", "tcp", 0);
-    av_dict_set(&options, "timeout", "10000000", 0);  // 10秒连接超时
-    av_dict_set(&options, "stimeout", "5000000", 0);  // 5秒读取超时
+    
+    // 根据是否为Docker环境调整超时设置
+    if (debug_mode) {
+        av_dict_set(&options, "timeout", "15000000", 0);  // Docker环境:15秒连接超时
+        av_dict_set(&options, "stimeout", "10000000", 0);  // 10秒读取超时
+        std::cout << "Docker环境超时配置: 连接15s, 读取50s" << std::endl;
+    } else {
+        av_dict_set(&options, "timeout", "10000000", 0);  // 本地环境:10秒连接超时
+        av_dict_set(&options, "stimeout", "5000000", 0);  // 5秒读取超时
+    }
+    
     av_dict_set(&options, "max_delay", "1000000", 0);  // 最大延迟1秒
     av_dict_set(&options, "reorder_queue_size", "10", 0);  // 减小缓冲队列
     av_dict_set(&options, "buffer_size", "65536", 0);  // 设置缓冲区大小
+    av_dict_set(&options, "user_agent", "RTSP-Client-Docker", 0);  // 设置用户代理
     
     // 设置超时时间(用于中断回调)
     start_time_us_ = av_gettime();