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

时间:2016-05-30 06:28:44

标签: docker

问题描述以及重现步骤: 我有一个用C ++编写的Server程序,使用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是&#34; 111&#34;这意味着连接被拒绝。

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

另外,我尝试了以下内容 1)我在给定的Linux系统中将我的客户端服务器程序作为正常进程运行,它完全正常。

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

请帮我解决这个问题。

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

好像你正在从客户端连接错误的IP地址。 运行服务器容器

现在使用 docker network inspect bridge 命令检查实际服务器的容器IP地址

现在尝试使用此IP地址连接客户端。

我认为docker Gateway将有172.17.0.1,如果你下次运行服务器,你可能会获得172.17.0.2作为服务器的IP。

希望它能解决你的问题。

答案 2 :(得分:0)

您可以通过DNS条目(每个容器名称一个)访问同一网络中的容器。

这是一个示例进行说明。在您的情况下,您将配置客户端容器以连接到服务器DNS条目服务器(类似于下面的myserver用法)。

$ docker network create javaapp
451905b63038719be32c3029dd229d02260fdc6f5fcca136c063556d3f3714d4

$ docker run -d --net javaapp --name myserver nginx
4b8c235789b2b262190f39d1ca2495304ca4ffc84321a127ac1bb9a0b748c717

$ docker run --net javaapp nathanleclaire/curl curl myserver:80
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:05 --:--:--     0



<!DOCTYPE html>
<html>`enter code here`
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>