0

I have a simple server-client setup where I want to transfer files back and forth. I have no issue when I use the following code to send a file from the client to the server. My problem is the code hangs without any errors when I try to then subsequently send a file back from the server to the client. Note that here I am trying to send a special type of file (hdf5).

The following is the server code:

import socket
import h5py
import io

HOST = 'localhost'
PORT = 3512  # Port

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen()
conn, address = s.accept()

#Receive the HDF5 file in chunks
chunks = []
while True:
    chunk = conn.recv(1024)
    if not chunk:
        break
    chunks.append(chunk)

#Read the hdf5 file 
with h5py.File(io.BytesIO(b''.join(chunks)), 'r') as f:
    print(f.keys())

    #If we stop up to here it works. 
    #But when I add the following, we never get past the conn.recv() part.
    img = f.id.get_file_image()
    conn.send(img)

Client side:

import socket
import h5py
import io

HOST = 'localhost'
PORT = 3512

sc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sc.connect((HOST, PORT)) # Connect to the port and host

#create hdf5 file with some dummy content
h5_f = h5py.File("test_file.h5", 'a')
grp = h5_f.create_group("Something")
grp.create_dataset("test", shape = (50,50))
h5_f.flush()

#Send the file
img = h5_f.id.get_file_image()
sc.send(img) # Send file image in chunks
    
#Receive a hdf5 file
chunks = []
while True:
    chunk = sc.recv(1024)
    if not chunk:
        break
    chunks.append(chunk)

# Load the HDF5 file from the received chunks
with h5py.File(io.BytesIO(b''.join(chunks)), 'r') as f:
    print(f.keys())

Running this code, it simply hangs. Why is receiving data on the client side an issue here?

I expected the client to receive the data, but it did not. It hangs without any error messages.

  • 1
    The server is reading to end of stream, which it is never getting because the client hasn't closed the connection. So when the client reads, the server hasn't sent anything. If you're only going to send one file in each direction, shutdown the socket for output after sending it in the client. If you're going to exchange > 1 file in either direction you need to send the length first and only read exactly that many bytes from the stream. – user207421 Jul 12 '23 at 00:19
  • Thank you! I understand now. I am able to transfer files back and forth now so long as I close and reopen the connections. – Rama Vasudevan Jul 12 '23 at 01:10
  • 1
    You should use `.sendall` instead of `.send`. The latter is not guaranteed to transmit all data. Your “solved” answer should also be in an answer, not edited into the question. – Mark Tolonen Jul 12 '23 at 01:37
  • 1
    Your solution won't work in general. Closing the socket and then opening anther one and hoping the server will send on this one instead of receiving is just wishful thinking. Do it with the shutdown as I suggested. That will always work. And you don't need to call `listen()` twice: I'd be surprised if that works. – user207421 Jul 12 '23 at 07:09

1 Answers1

-1

Thank you user207421 for the explanation. And Mark Tolonen for the clarification.

The working scripts now close all connections and then re-establishes them as needed.

NB: On my Dell laptop with Windows, to close this server with ctrl+c, you need to add some extra handling (refer to https://stackoverflow.com/a/52941752/8448563 )

Server:

import socket
import h5py
import io

HOST = 'localhost'
PORT = 3512  # Port

while True:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((HOST, PORT))
    s.listen()
    conn, address = s.accept()

    #Receive the HDF5 file in chunks
    chunks = []
    while True:
        chunk = conn.recv(1024)
        if not chunk:
            break
        chunks.append(chunk)
    #Close the connection after receiving
    s.close()
    conn.close()

    #Read the hdf5 file 
    with h5py.File(io.BytesIO(b''.join(chunks)), 'r') as f:
        print(f.keys())
        img = f.id.get_file_image()
    
    #Now send it back
    #First, open the connection again
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((HOST, PORT))
    s.listen()
    conn, address = s.accept()
    conn.sendall(img)

    #Close off the connections
    conn.close()    
    s.close()

Client:

import socket
import h5py
import io
import os


HOST = 'localhost'
PORT = 3512

sc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sc.connect((HOST, PORT)) # Connect to the port and host

#create hdf5 file with some dummy content
h5_f = h5py.File("test_file.h5", 'a')
grp = h5_f.create_group("Something")
grp.create_dataset("test", shape = (50,50))
h5_f.flush()

#Send the file
img = h5_f.id.get_file_image()
sc.sendall(img) # Send file image in chunks
#Close tehe connection
sc.close()

#Now time to receive, open connection
sc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sc.connect((HOST, PORT)) # Connect to the port and host
#Receive a hdf5 file
chunks = []
while True:
    chunk = sc.recv(1024)
    if not chunk:
        break
    chunks.append(chunk)

# Load the HDF5 file from the received chunks
with h5py.File(io.BytesIO(b''.join(chunks)), 'r') as f:
    print(f.keys())

sc.close()