'Python Sockets - Keeping server socket alive after it's done receiving data

I have a TCP/IP communication in Python where the client sends the image to the destination that is the server. After receiving the image is received, a response is sent back to the client informing that the image has been successfully received. My problem is that I would like to keep the server socket open for when a new image is sent by the client, given that in my situation only 1 frame at once, every hour or so. Thus, the server socket needs to remain open to listen for a new connection from the client, but I can't figure out how to do it the right way.

My current code that receives an image and save is this:

Client that sends a frame:

import numpy as np
import cv2
from PIL import Image
import base64
import socket
from os.path import dirname, join
from com.chaquo.python import Python

def main(data):
    s = socket.socket()
    s.connect(("192.168.0.16", 9999))

    decoded_data = base64.b64decode(data)

    files_dir = str(Python.getPlatform().getApplication().getFilesDir())
    filename = join(dirname(files_dir), 'image.PNG')

    out_file = open(filename, 'wb')
    out_file.write(decoded_data)



    filetosend = open(filename, "rb")
    data = filetosend.read(512)
    while data:
        print("Sending...")
        s.send(data)
        data = filetosend.read(512)
    filetosend.close()
    s.send(b"DONE")
    print("Done Sending.")
    msg = s.recv(512).decode()
    print(msg)
    s.shutdown(2)
    s.close()

    return msg

Server that receives a frame from the client:

import socket
import cv2
import numpy as np
import os
import uuid

img_dir = '/home/pi/Desktop/frames_saved/'
img_format = '.png'
filename = str(uuid.uuid4())
s = socket.socket()
s.bind(("192.168.0.16", 9999))
s.listen(1)
c,a = s.accept()
filetodown = open(img_dir+filename+img_format, "wb")
while True:
   print("Receiving....")
   data = c.recv(512)
   print(data)
   if b"DONE" in data:
       print("Done Receiving.")
       break
   filetodown.write(data)
filetodown.close()
c.send("Thank you for connecting.".encode())
c.shutdown(2)
c.close()
s.close()

This works fine for me, however if I attempt to add a while loop to keep the socket open, like this:

import socket
import cv2
import numpy as np
import os
import uuid


filename = str(uuid.uuid4())
s = socket.socket()
s.bind(("192.168.0.16", 9999))
s.listen(1)
while True:
    c,a = s.accept()
    img_dir = '/home/pi/Desktop/frames_saved/'
    img_format = '.png'
    filetodown = open(img_dir+filename+img_format, "wb")
    while True:
       print("Receiving....")
       data = c.recv(512)
       print(data)
       if b"DONE" in data:
           print("Done Receiving.")
           break
       filetodown.write(data)
    filetodown.close()
    c.send("Thank you for connecting.".encode())
    c.shutdown(2)
    c.close()
    s.close()

This will give the following error:

Traceback (most recent call last):
  File "server.py", line 13, in <module>
    c,a = s.accept()
  File "/usr/lib/python3.7/socket.py", line 212, in accept
    fd, addr = self._accept()
OSError: [Errno 9] Bad file descriptor


Solution 1:[1]

s.listen(1)
while True:
    c,a = s.accept()
    ...
    c.close()
    s.close()                   <<<< WRONG!

You should not close the server socket inside the loop. Otherwise it cannot call accept again on this socket, leading to Bad file descriptor in accept.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Steffen Ullrich