主机到Docker容器的远程套接字故障

时间:2019-05-05 07:07:54

标签: docker sockets networking containers port

我正在尝试在主机和Docker容器之间传递一条简单的消息。

我首先使用主机网络驱动程序创建了docker容器:
docker run -t -d --network host --name cfalcon ubuntu

接下来,我进入了容器:
docker exec -it cfalcon

我使用以下命令将主机IP标识为192.168.0.109,并将容器IP标识为172.17.0.1。 hostname -I

我在〜/ Documents / tcp_server.c中用以下代码在容器中创建了一个文件:

TCP_SERVER.C

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/socket.h>
#include <sys/types.h>

#include <arpa/inet.h>
#include <netinet/in.h>

int main(int argc, char* argv[]) {

    char address[] = "192.168.0.109";
    // Creating Server Socket
    int server_socket;
    server_socket = socket(AF_INET, SOCK_STREAM, 0);

    // Defining Server Address
    struct sockaddr_in server_address;
    server_address.sin_family = AF_INET;
    // Specify the port, 9001 seems safe
    server_address.sin_port = htons(9001);
    server_address.sin_addr.s_addr = inet_addr(address);

    // Binding our Socket to our Specified IP, 192.168.0.109
    bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address));

    // Listen() Function Begins Listening for a Connection
    listen(server_socket, 1);

    // Ability to Accept Connections
    int client_socket;
    client_socket = accept(server_socket, NULL, NULL);

    char server_message[256] = "Its-a me, a-mario!";

    // Send a message with send()
    send(client_socket, server_message, sizeof(server_message), 0);

    close(server_socket);

    return 0;
}

回到主机,我决定使用以下代码在〜/ Documents / tcp_client.c中创建一个新文件:

TCP_CLIENT.C

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/socket.h>
#include <sys/types.h>

#include <arpa/inet.h>
#include <netinet/in.h>

int main(int argc, char* argv[]) {
    char address[] = "172.17.0.1";
    // Creating a Socket
    int network_socket;
    // socket(domain of socket (generally AF_INET, a constant), TCP socket, protocol)
    network_socket = socket(AF_INET, SOCK_STREAM, 0);

    // Specifying an Address for the Socket (Address family is same as parameter one of socket())
    struct sockaddr_in server_address;
    server_address.sin_family = AF_INET;

    // Specify the port, 9001 seems safe
    server_address.sin_port = htons(9001);
    server_address.sin_addr.s_addr = inet_addr(address);

    // Returns an integer for error handling
    int connection_status = connect(network_socket, (struct sockaddr *) &server_address, sizeof(server_address));
    // Error Handling
    if (connection_status == -1) {
        printf("There was an error making a connection to the remote socket.\n\n");
    }

    // If we send data, we receive a response from the server in recv
    char server_response[256];
    recv(network_socket, &server_response, sizeof(server_response), 0);

    // Printing the Server's Response
    printf("The server responded with: %s\n", server_response);

    // Avoiding data leaks
    close(network_socket);

    return 0;
}

不幸的是,我没有收到“ Its-a me,a-Mario!”,而是“与远程套接字建立连接时出错”。

我相信我可以使用各自的IP和相同的端口号完美地将两者链接在一起,但是我似乎没有。如果您对我的困境有任何指导,请告诉我。

编辑:更新!我在容器上安装了Netcat,并在主机和容器之间建立了连接。
主持人:$ nc -l 9001
容器:$ nc localhost 9001
在以下提示中从容器发送的任何消息都会到达我的主机,这告诉我这仅仅是我的代码错误。

1 个答案:

答案 0 :(得分:0)

在最低级别,您的服务器代码 bind (2)到192.168.0.9,但是您的客户端代码 connect (2)到172.17.0.1。服务器将仅接受与其绑定到的单个地址的连接。如果您使用的是Docker主机网络,则从网络的角度来看,服务器进程与主机上运行的任何其他进程都没有区别,而172.17.0.1也可能到达主机,因为它的地址并不完全相同,您的连接将被拒绝。

如果服务器在Docker容器中运行,并且客户端直接在同一主机上运行:

  1. 绑定(2)到0.0.0.0。 (绑定到127.0.0.1将使该过程无法从容器外部访问;容器专用IP地址是不可预测的。)
  2. 请勿使用--net host启动容器。请使用适当的-p选项将其启动,以将容器端口映射到某个主机端口。例如-p 9001:9001
  3. 从客户端(不是在Docker中运行)在同一主机上,连接(2)到127.0.0.1端口9001。在其他主机(Docker或其他主机)上,使用第一台主机的名称。

如果客户端在同一主机上的其他容器中运行:

  1. 绑定(2)到0.0.0.0。
  2. docker create network something。您不需要任何其他参数,但是您确实需要创建网络。
  3. 当您同时docker run使用两个容器时,请以与您先前创建的网络相匹配的--net something和有用的--name来启动它们。
  4. 在客户端中,使用 getaddrinfo (3)查找服务器的容器名称;然后连接(2)到该sockaddr

请注意,这些路径均不涉及查找容器专用IP地址(在普通的“连接到该主机名”路径中作为低级详细信息除外)。这会定期更改(无论何时删除和重新创建容器),都无法从脱离主机访问,甚至在某些Docker设置中也无法从主机控制台访问。永远不需要进行查找。

还要注意,这两个路径都不涉及docker exec。这是一个有用的调试工具,但通常不是核心容器工作流程的一部分。 (如果您发现自己“ docker run是一个容器,然后立即docker exec”,通常应该更改容器启动顺序以执行docker exec本身的所有操作。)