Docker:每个作为容器运行的客户端服务器程序无法使用 POSIX 套接字 API 相互通信

标签 docker

问题描述及重现步骤: 我有一个用 C++ 编写的服务器程序,使用 posix Socket API。用于构建服务器镜像的 Dockerfile 是:

$ cat Dockerfile
FROM gcc:4.9
WORKDIR /home/vikrana
COPY . .
EXPOSE 1001
RUN g++ -o testcplusplus testprogram.cpp
ENV PATH /home/vikrana:$PATH
ENTRYPOINT ["testcplusplus", "1001"]

服务器程序如下:

#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>


using namespace std;

int main(int argc, char *argv[])
{
  int sockfd, newsockfd, portno;
  socklen_t clilen;
  char buffer[256];
  struct sockaddr_in serv_addr, cli_addr;
  int n;
  if(const char* env_p = std::getenv("PATH"))
      std::cout << "Your PATH is: " << env_p << '\n';
  if(argc < 2)
  {
      cout<<"Number of arguments not correct\n";
      exit(1);
  }
  cout<<argv[1]<<"\n";
  cout<<"Creating socket\n";
  struct protoent *proto;
  proto = getprotobyname("tcp");
  sockfd=socket(AF_INET, SOCK_STREAM, proto->p_proto);
  cout<<"Socket created successfully\n";

  portno=atoi(argv[1]);
  serv_addr.sin_family=AF_INET;
  serv_addr.sin_addr.s_addr=inet_addr("0.0.0.0");
  cout<<"Port No:"<<portno<<"\n";
  serv_addr.sin_port=htons(portno);
  cout<<"Starting binding socket to a port\n";
  if (bind(sockfd, (struct sockaddr *) &serv_addr,
            sizeof(serv_addr)) < 0)
  {
      cout<<"Error while binding\n";
      exit(1);
  }
  cout<<"Bind is successful\n";
  cout<<"Listening to port\n";
  int x =listen(sockfd,5);
  if(x<0)
  {
   cout<<"Error on listening to port 1001\n";
   cout<<errno<<"\n";
   cout<<strerror(errno)<<"\n";
   close(sockfd);
   exit(1);
 }
 clilen=sizeof(cli_addr);
 cout<<"Accepting connection\n";
 newsockfd=accept(sockfd,(struct sockaddr *)&cli_addr,&clilen);
 if(newsockfd <0)
 {
    cout<<"Error while accepting a new connection\n";
    close(sockfd);
    exit(1);
 }
 cout<<"Accepted the connection\n";
 while(true)
 {
    memset(&buffer,0,sizeof(buffer));
    cout<<"Reading from socket to buffer\n";
    n=read(newsockfd,buffer,255);
    if(n<0)
    {
        cout<<"Erro reading from socket\n";
        close(sockfd);
        close(newsockfd);
        exit(1);
    }
    cout<<"Message received to the server:"<<buffer<<"\n";
    n=write(newsockfd,"I got your message\n",19);
    if(n<0)
    {
       cout<<"Error writing into socket\n";
       close(sockfd);
       close(newsockfd);
       exit(1);
    }
  }
 close(sockfd);
 close(newsockfd);
 return 0;
 }

以下是我用来在容器中运行服务器程序的 Docker 命令:

 $ docker run --net=user_def_nw -ti -P --name server1 my-server-app

在运行上面的命令时,容器会附加 user_def_nw 并为容器分配一个 IP 地址。

另一方面,以下是我使用 posix Socket API 用 C++ 编写的客户端程序的详细信息。 用于创建客户端镜像的 DockerFile:

$ cat Dockerfile
FROM gcc:4.9
WORKDIR /home/vikrana
COPY . .
RUN g++ -o testcplusplus testclientprogram.cpp
ENV PATH /home/vikrana:$PATH
ENTRYPOINT ["testcplusplus", "0.0.0.0", "1001"]

客户端程序代码如下:

#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>

using namespace std;

int main(int argc, char *argv[])
{
  int sockfd, newsockfd, portno;
  struct sockaddr_in server;
  char message[256], server_reply[2000];
  if(const char* env_p = std::getenv("PATH"))
          std::cout << "Your PATH is: " << env_p << '\n';
  struct protoent *proto;
  proto = getprotobyname("tcp");
  sockfd=socket(AF_INET, SOCK_STREAM, proto->p_proto);
  cout<<"socket created\n";

  cout<<argv[1]<<"\n";
  cout<<argv[2]<<"\n";
  portno=atoi(argv[2]);
  cout<<portno<<"\n";
  server.sin_family=AF_INET;
  server.sin_addr.s_addr=inet_addr(argv[1]);
  server.sin_port=htons(portno);
  memset(server.sin_zero, '\0', sizeof server.sin_zero);

  cout<<"connecting to server\n";
   int x =connect(sockfd, (struct sockaddr *)&server, sizeof(server));
   cout<<"Connect Return Code:"<<x<<"\n";
  if(x<0)
  {
      cout<<"Connect Failed\n";
      cout<<errno<<"\n";
      cout<<strerror(errno)<<"\n";
      exit(1);
  }
  cout<<"Connected\n";
  while(1)
  {
      cout<<"Enter Message:";
      cin>>message;

      if(send(sockfd,message,strlen(message),0) < 0)
      {
          cout<<"Send Failed\n";
          exit(1);
      }
      sleep(2);

      if(recv(sockfd,server_reply,2000,0) < 0)
      {
         cout<<"Recv Failed\n";
         break;
      }

      cout<<"Server Reply:"<<server_reply<<"\n";
     }
  close(sockfd);
   return 0;
 }

以下是我用来在容器中运行客户端程序的 Docker 命令:

 $ docker run --net=user_def_nw -ti --name cli1 my-client-app

在运行上述命令时,注意到客户端无法连接到监听端口 1001 的服务器。

连接 API 返回的错误代码是“111”,这意味着连接被拒绝。

我的理解是因为两个容器即 server1 和 cli1 都连接到同一个用户定义网络“user_def_nw”桥接网络,它们应该能够通过 Socket 相互通信。但是这里连接 API 本身无法与服务器建立连接。

此外,我尝试了以下方法 1) 我在给定的 Linux 系统中将我的客户端服务器程序作为正常进程运行,它运行得非常好。

2) 我将我的基础镜像制作为 ubuntu,并在其顶部安装了 g++ 编译器,然后将我的客户端和服务器程序作为独立的容器运行,仍然出现与上面报告的相同的错误。

请帮我解决这个问题。

最佳答案

在用户定义的网络中,您可以通过引用容器名称来连接两个容器。在您的客户端应用程序 dockerfile 中,尝试将 0.0.0.0 替换为 server1。

关于Docker:每个作为容器运行的客户端服务器程序无法使用 POSIX 套接字 API 相互通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37518977/

相关文章:

amazon-web-services - NGINX 存储库中所需的 docker 镜像文件的完整路径

Windows 上的 Docker 使用 Hyper-V。如何在拉取大量图像时动态地向 docker 添加空间或扩展到硬盘驱动器

python - 使用 pip 在 docker 容器中安装 opencv 时遇到问题

python - 带有 Gunicorn Dockerized 的 Flask 应用程序,监听 : http://0. 0.0.0 :8000, 但 URL 没有响应

docker - 如何在我的 docker 构建中包含本地包依赖项?

docker - 如何在 ubuntu 中使用 fscrawler?

opencv - 如何在 docker (debian :jessie)) 上为 python3.5 安装 openCV

由于 "permission denied",docker compose down 失败

c# - 如何在docker中设置dotnet core的环境?

linux - docker-compose.yml 在以点 (.) 开头的文档上使用卷