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

Docker部署C++服务端与Python客户端连接失败求助

Docker下服务端与客户端连接故障排查求助

我已经花了4小时排查问题,但重复操作仍无法解决Docker环境下服务端与客户端的运行故障。我已在docker-compose中配置端口映射和暴露,但连接始终失败,且VS Code端口栏未显示该端口被占用。以下是我的配置与代码:

docker-compose.yml

services:
  server:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: server
    volumes:
      - ./data:/app/data
    ports:
      - "3000:3000"
    networks:
      - app_network
    stdin_open: true
    tty: true

  client:
    build:
      context: .
      dockerfile: Dockerfile.client
    container_name: client
    networks:
      - app_network
    stdin_open: true
    tty: true

networks:
  app_network:
    name: netflix_app_network
    driver: bridge

服务端Dockerfile

# Use an official image with CMake and GCC pre-installed
FROM ubuntu:20.04

# Set environment variables to prevent interactive prompts during package installation
ENV DEBIAN_FRONTEND=noninteractive

# Install necessary tools and dependencies
RUN apt-get update && apt-get install -y \
    build-essential \
    cmake \
    git \
    wget \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Copy the entire project into the container
RUN mkdir -p /app/data
COPY . /app

# Set the working directory to the project root
WORKDIR /app

# Create a build directory, configure, and build the project
RUN mkdir -p build && \
    cd build && \
    cmake .. && \
    cmake --build .

# Expose server's port
EXPOSE 3000

VOLUME /app/data

# Set the default command to run the application
CMD ["./build/App"]

客户端Dockerfile(手动运行客户端)

FROM python:3.9-slim

# Set the working directory in the container
WORKDIR /app

# Copy the client code into the container
COPY . /app

# Install any necessary dependencies
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt

# Command to run the client program
CMD ["tail", "-f", "/dev/null"]

服务端代码

#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <iostream>
#include <cstring> // For memset

TCPServer::TCPServer(int port, IClientHandler* handler)
    : port(port), clientHandler(handler) {
    serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket < 0) {
        perror("Failed to create socket");
        exit(EXIT_FAILURE);
    }

    sockaddr_in serverAddr{};
    memset(&serverAddr, 0, sizeof(serverAddr)); // Clear memory
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY; // Bind to all available IPv4 addresses
    serverAddr.sin_port = htons(port);

    if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
        perror("Bind failed");
        close(serverSocket);
        exit(EXIT_FAILURE);
    }
}

TCPServer::~TCPServer() {
    close(serverSocket);
}

void TCPServer::start() {
    if (listen(serverSocket, 5) < 0) {
        perror("Listen failed");
        exit(EXIT_FAILURE);
    }
    
    std::cout << "Server listening on port " << port << std::endl;

    while (true) {
        std::cout << "hi" << port << std::endl;
        sockaddr_in clientAddr{};
        socklen_t clientLen = sizeof(clientAddr);
        int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientLen);

        if (clientSocket < 0) {
            perror("Accept failed");
            continue; // Continue accepting connections
        }

        clientHandler->handleClient(clientSocket);
        close(clientSocket); // Close the client socket after handling it
    }
}

客户端代码

import socket

class TCPClient:
    def __init__(self, server_address: str, port: int):
        self.server_address = server_address
        self.port = port
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    def connect(self):
        try:
            self.client_socket.connect((self.server_address, self.port))
            print(f"Connected to server at {self.server_address}:{self.port}")
        except Exception as e:
            print(f"Failed to connect: {e}")
            self.client_socket.close()
            raise

    def send(self, message: str):
        try:
            self.client_socket.sendall(message.encode('utf-8'))
        except Exception as e:
            print(f"Error sending message: {e}")

    def receive(self):
        try:
            response = self.client_socket.recv(1024).decode('utf-8')
            return response
        except Exception as e:
            print(f"Error receiving response: {e}")
            return None

    def close(self):
        self.client_socket.close()
        print("Connection closed.")

if __name__ == "__main__":
    client = TCPClient("127.0.0.1", 3000)  # Replace with the server's IP and port
    try:
        client.connect()
        while True:
            command = input("Enter command: ")
            client.send(command)
            response = client.receive()
            if response:
                print(f"Server response: {response}")
    except Exception as e:
        print(f"An error occurred: {e}")
    finally:
        client.close()

排查建议

  1. 修正客户端连接地址:容器内的127.0.0.1指向自身,而非服务端容器。将客户端代码中的连接地址改为服务端容器名server,Docker Compose会在自定义网络中自动解析容器名到对应IP。
  2. 验证服务端状态:
    • 执行docker logs server查看日志,确认是否输出Server listening on port 3000,若没有则检查编译是否正常、./build/App是否存在。
    • 进入服务端容器docker exec -it server bash,执行netstat -tulpn确认端口3000处于监听状态。
  3. 测试容器间网络连通性:
    • 进入客户端容器docker exec -it client bash,先执行ping server确认网络可达,再用telnet server 3000测试端口是否开放。
  4. 明确端口映射作用:ports: "3000:3000"仅用于宿主机访问服务端,容器间通信无需依赖该映射,直接通过自定义网络访问即可。
  5. 规范客户端运行流程:客户端容器用tail -f /dev/null保持运行,需手动进入容器执行python client.py,确保使用修正后的服务端地址。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 14:48:12