In a docker network I am trying to communicate between two containers using python sockets (to send packets). Pinging works but python sockets library does not work.
The error:
line 6: conn, addr = sock.connect(('172.168.1.2', 4000))
TypeError: 'NoneType' object is not iterable
First python3 receive.py is run in container1. Then python3 send.py is run in container 2. Container 1 prints "accepted" and then nothing else. Container 2 errors as mentioned above.
This network is a user-defined network with it's own subnet and default gateway. This error does not occur with the same exact code when I use it to connect to my raspberry pi, but it errors with container communication.
All of the code:
container1:
import socket
def receive():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("", 4000))
s.listen(2)
conn, addr = s.accept()
print("accepted")
print(bytes.decode(conn.recv(1024)))
container 2:
import socket
def send():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
command = "bridge test!"
conn, addr = sock.connect(('172.168.1.2', 4000))
conn.sendall(command)
To setup the network:
docker network create --subnet 172.168.1.0/24 testNetwork
docker network connect testNetwork container1
docker network connect testNetwork container2
I got the IP addresses of the containers from docker inspect (plus pinging them works) Please help! Thanks!
You have a couple of issues.
socket.connect
doesn't return anything. It returns None
. You think it returns a tuple of conn, addr
. Python tries to deconstruct whatever is returned into a tuple by iterating over it and you get the error:
TypeError: 'NoneType' object is not iterable
socket.sendall accepts bytes not a str
. Convert by
sock.sendall(command.encode())
Here's the fixed send.py
:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
command = "bridge test!"
x, y = sock.connect(('172.168.1.2', 4000))
sock.sendall(command.encode())
You might want to try the docker api for python. https://github.com/docker/docker-py.git
Here is an example.
#!/usr/bin/python3
import docker
import requests
def main():
# Connect to the default unix socket (/var/run/docker.sock)
client = docker.from_env()
#Pull the nginx:alpine image
client.images.pull('nginx:alpine')
#Define some test parameters, our first HTTP port and the number of containers
portstart = 10000
count = 1000
#Create and start 'count' number of containers. Map container port 80 to an external port.
for a in range(1,count+1):
container = client.containers.create('nginx:alpine',ports={'80/tcp':portstart+a})
container.start()
print('Created container number {} name: {}'.format(a,container.name))
#Get a list of all the running containers (best you don't run this script on a system which has existing containers running)
#Iterate through the list, pick out the remote port, and perform a GET request to it to check nginx is online. If the status code is 200, we must be successful!
container_list = client.containers.list()
count = 0
for container in container_list:
port = container.attrs['HostConfig']['PortBindings']['80/tcp'][0]['HostPort']
r = requests.get('http://127.0.0.1:{}'.format(port))
if(r.status_code == 200):
print('Container {} is alive and working on port {}!'.format(container.name,port))
count += 1
else:
print('Container {} is dead :( Code: {}'.format(container.name,r.status_code))
print('Summary: Online Containers: {} Offline Containers: {}'.format(count,len(container_list)-count))
print('Removing containers...')
#Let's clean up and put our toys back in the toybox.
for container in container_list:
container.stop()
container.remove()
if __name__ == "__main__":
main()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With