Client Server Program each running as a Container Not Able to Communicate with each Other Using POSIX Socket API

Expected behavior

Client and Sever Program (written in C++) each running as a container should be able to communicate with each other over a given user defined network using POSIX socket API.

Actual behavior

Client and Server Program each running as an independent container within a same DOCKER_HOST are not able to communicate with each other over a given user defined network using POSIX socket API.

Information

  • host distribution and version : Windows 7
    docker version:

  • Client:
    Version: 1.10.3
    API version: 1.22
    Go version: go1.5.3
    Git commit: 20f81dd
    Built: Thu Mar 10 21:49:11 2016
    OS/Arch: windows/amd64

Server:
Version: 1.10.3
API version: 1.22
Go version: go1.5.3
Git commit: 20f81dd
Built: Thu Mar 10 21:49:11 2016
OS/Arch: linux/amd64

docker info:

Containers: 31
Running: 0
Paused: 0
Stopped: 31
Images: 209
Server Version: 1.10.3
Storage Driver: aufs
Root Dir: /mnt/sda1/var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 190
Dirperm1 Supported: true
Execution Driver: native-0.2
Logging Driver: json-file
Plugins:
Volume: local
Network: null host bridge
Kernel Version: 4.1.19-boot2docker
Operating System: Boot2Docker 1.10.3 (TCL 6.4.1); master : 625117e - Thu Mar 10
22:09:02 UTC 2016
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 996.1 MiB
Name: default
ID: NKOP:JPNZ:6X7J:SZHG:YUNP:35JK:JWT5:4KME:ANGS:FJQD:I6RR:YO3L
Debug mode (server): true
File Descriptors: 10
Goroutines: 22
System Time: 2016-05-23T11:45:46.31574063Z
EventsListeners: 0
Init SHA1:
Init Path: /usr/local/bin/docker
Docker Root Dir: /mnt/sda1/var/lib/docker
Labels:
provider=virtualbox

Steps to reproduce the behavior

I have a Server program written in C++ ,using posix Socket API. The Dockerfile used for building the Server image is:

$ 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”]

Below is the code for the Server program: ( Not allowing new users to upload the file ):

#include
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include
#include
#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;
const char
env_p1;
if(const char* env_p = std::getenv(“PATH”))
std::cout << "Your PATH is: " << env_p << ‘\n’;

if(env_p1 = std::getenv(“HOSTNAME”))
std::cout<< “Your HOSTNAME is: “<< env_p1 << ‘\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”;
//memset(&serv_addr, 0 , sizeof(serv_addr));
portno=atoi(argv[1]);
serv_addr.sin_family=AF_INET;
//serv_addr.sin_addr.s_addr=inet_addr(env_p1);
serv_addr.sin_addr.s_addr=inet_addr(“0.0.0.0”);
//serv_addr.sin_addr.s_addr=INADDR_ANY;
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”,18);
if(n<0)
{
cout<<“Error writing into socket\n”;
close(sockfd);
close(newsockfd);
exit(1);
}
}
close(sockfd);
close(newsockfd);
return 0;
}

Following is the Docker command I am using to run my server program in the container:

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

On running above command the container gets attached with user_def_nw and an IP address is assigned to the container.

On the other hand following are the details of my Client program written in C++ using posix Socket API. DockerFile to create client image:

$ 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”]

Below is the code for the client program:

#include
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include
#include
#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;
}

Following is the Docker command I am using to run my client program in the container:

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

On running the above command it is noticed Client is not able to connect to the server listening at port 1001.

The error code return by the connect API is “111” which means, connection refused.

My understanding is since both the containers namely server1 and cli1 are attached to the same user defined network “user_def_nw” bridge network, they should be able to communicate with each other over Socket. But here connect API itself is failing to establish connection with the Server.

Also, I tried the following :

  1. I ran my client server program as a normal process in a given Linux system, it works perfectly fine.

  2. I made my base image as ubuntu and top of it installed g++ compiler, and then ran my client and server program as independent containers, still the same error as reported above I am getting.

Please help me in resolving this issue.

Connection refused because
the server adress can’t be 0.0.0.0
serv_addr.sin_addr.s_addr=inet_addr(“0.0.0.0”); must be some thing

Run the Docker network inspect user_def_nw to get the ip associated with the server container. it must look like “172.18.0.2”