2

I am writing a TCP concurrent (process based-concurrency) server which accepts a download command. The client should download a file from the server, as of right now I have the filename hard-coded to download in order to test my download algorithm.

I looked up a sample download algorithm and am using the while loop used in that code.

I think my problem is that is that one of the while loops (or maybe both of them) is getting hung up and won't end. I believe that It is the client side, and it is likely waiting for more fileContent.

server

            file = open('download.txt','rb+')
            print "Opened File: " , file.name

            fileContent = file.read(1)
            clientsocket.send(fileContent)
            while (fileContent):
                print "iteration", fileContent
                clientsocket.send(fileContent)
                fileContent = file.read(1)                  
            file.close()

client side

    print "Attempting download..."
    f = open('downloaded.txt' , 'wb+')      
    print "Opened File: " , f.name
    fileContent = s.recv(1)
    while (fileContent):
        print "iteration", fileContent
        f.write(fileContent)
        fileContent = s.recv(1)
    print "Download Complete"
    f.close()

I have accomplished the file transfer without a while loop, using code such as

 f.open(file)
 fContent = f.read(1024)
 client.send(fContent)
 f.close

 f.open(file)
 fContent = server.recv(1024)
 f.write(fContent)
 f.close 

but I know this to cause problems if the file is bigger than the buffer size.

This is a concurrent server that uses an individual process to handle each connection. (I don't believe this should affect my current problem but I am new to concurrency and figured I would mention it.)

Does anyone know why my while loops aren't ending? Or does anyone know of something else I might be doing wrong? Thanks in advance!

edit:

My output:

cli

Attempting download...
Opened File:  downloaded.txt
iteration t
iteration h
iteration i
iteration s
iteration
iteration i
iteration s
iteration
iteration a
iteration
iteration f
iteration i
iteration l
iteration e
iteration

serv

Recived  dl from:  ('127.0.0.1', 38161)  |  2015-12-06 13:07:12.835998
Opened File:  download.txt
iteration t
iteration h
iteration i
iteration s
iteration
iteration i
iteration s
iteration
iteration a
iteration
iteration f
iteration i
iteration l
iteration e
iteration

The client becomes stuck, and I have to ctrl z it out. The server will continue to accept connections. I just realized that I can add a simple print statement after the server's while loop to check if the server's while loop finished.

2nd edit:

The server is not getting hung up (it successfully displays the message after the loop). This leads me to believe that the client is calling recv() and waiting for more fileContent.

3rd edit:

The read/write buffer was only at 1 for testing purposes.

Community
  • 1
  • 1
Greg
  • 103
  • 2
  • 9
  • On the server side, you don't close the socket so the client doesn't know the file ended. Add `clientsocket.shutdown(socket.SOCK_RDWR)` and then `clientsocket.close()`. – tdelaney Dec 06 '15 at 19:10
  • @tdelaney The server should continue accepting commands. I don't want the connection to terminate after the download completes, wouldn't this happen if I close the socket? – Greg Dec 06 '15 at 19:13
  • 1
    Yes, it would terminate. But if you want to keep the socket open you've got a bigger problem because you still need a way to tell the client that the transfer is complete. A common way to do that is to use the `struct` module to define a message structure (say, a flags field to say whether this is the last fragment plus a length) followed by exactly length bytes from the file. The client would read the header then read exactly length bytes and repeat until the flags say to stop. – tdelaney Dec 06 '15 at 19:17
  • You also never actually close `f.close -> f.close()` – Padraic Cunningham Dec 06 '15 at 20:12

1 Answers1

1

Sending a file byte by byte might be very slow. Best use shutil.copyfileobj, that handles the transfer for you:

def send_file(socket, filename):
    with open('download.txt','rb') as inp:
        print "Opened File: " , file.name
        out = socket.makefile('wb')
        shutil.copyfileobj(inp, out)

def recv_file(socket, filename):
    with open('download.txt','wb') as out:
        print "Opened File: " , file.name
        inp = socket.makefile('rb')
        shutil.copyfileobj(inp, out)
Daniel
  • 42,087
  • 4
  • 55
  • 81
  • 1
    That is much more useful than what I am trying to do, however I would like to accomplish it they way above. It is for a school project and I am trying to mimic 'c' as much as I can, and I don't believe 'c' has that call :( – Greg Dec 06 '15 at 18:40