47

I've successfully been able to copy the file contents (image) to a new file. However when I try the same thing over TCP sockets I'm facing issues. The server loop is not exiting. The client loop exits when it reaches the EOF, however the server is unable to recognize EOF.

Here's the code:

Server

import socket               # Import socket module

s = socket.socket()         # Create a socket object
host = socket.gethostname() # Get local machine name
port = 12345                 # Reserve a port for your service.
s.bind((host, port))        # Bind to the port
f = open('torecv.png','wb')
s.listen(5)                 # Now wait for client connection.
while True:
    c, addr = s.accept()     # Establish connection with client.
    print 'Got connection from', addr
    print "Receiving..."
    l = c.recv(1024)
    while (l):
        print "Receiving..."
        f.write(l)
        l = c.recv(1024)
    f.close()
    print "Done Receiving"
    c.send('Thank you for connecting')
    c.close()                # Close the connection

Client

import socket               # Import socket module

s = socket.socket()         # Create a socket object
host = socket.gethostname() # Get local machine name
port = 12345                 # Reserve a port for your service.

s.connect((host, port))
s.send("Hello server!")
f = open('tosend.png','rb')
print 'Sending...'
l = f.read(1024)
while (l):
    print 'Sending...'
    s.send(l)
    l = f.read(1024)
f.close()
print "Done Sending"
print s.recv(1024)
s.close                     # Close the socket when done

Here's the screenshot:

Server Server

Client Client

Edit 1: Extra data copied over. Making the file "not complete." The first column shows the image that has been received. It seems to be larger than the one sent. Because of this, I'm not able to open the image. It seems like a corrupted file.

File sizes

Edit 2: This is how I do it in the console. The file sizes are the same here. Python Console Same file sizes

Swaathi Kakarla
  • 2,227
  • 1
  • 19
  • 27

7 Answers7

38

Client need to notify that it finished sending, using socket.shutdown (not socket.close which close both reading/writing part of the socket):

...
print "Done Sending"
s.shutdown(socket.SHUT_WR)
print s.recv(1024)
s.close()

UPDATE

Client sends Hello server! to the server; which is written to the file in the server side.

s.send("Hello server!")

Remove above line to avoid it.

falsetru
  • 357,413
  • 63
  • 732
  • 636
  • Thanks for helping me out! I tried this, but it's still in the loop. The problem I think is that the client send is never sending the EOF, because once it reaches EOF, it's breaking out of the loop and never sending it to the server. Is that the error? – Swaathi Kakarla Dec 02 '14 at 04:37
  • 2
    @SwaathiK, Ah, client is waiting for the data, after it finish sending. I updated the answer. Please check it out. – falsetru Dec 02 '14 at 04:38
  • Thanks so much! It worked like a charm. But I just have one more question, why is the file not being reconstructed on the server side? It copies everything, but the file is not complete. I hope I'm making sense. – Swaathi Kakarla Dec 02 '14 at 04:49
  • @SwaathiK, What does it mean by `the file is not compelte`? – falsetru Dec 02 '14 at 04:52
  • When I do the same operation in the console, it seems to work. I've added the screenshots to the question. – Swaathi Kakarla Dec 02 '14 at 05:00
  • @SwaathiK, Please replace `send`s with `sendall`, and try again. – falsetru Dec 02 '14 at 05:01
  • It's (torecv.png) still the same file size, 58,055 bytes. :( – Swaathi Kakarla Dec 02 '14 at 05:04
6

Remove below code

s.send("Hello server!")

because your sending s.send("Hello server!") to server, so your output file is somewhat more in size.

Rama Krishna
  • 275
  • 3
  • 12
2

You can send some flag to stop while loop in server

for example

Server side:

import socket
s = socket.socket()
s.bind(("localhost", 5000))
s.listen(1)
c,a = s.accept()
filetodown = open("img.png", "wb")
while True:
   print("Receiving....")
   data = c.recv(1024)
   if data == b"DONE":
           print("Done Receiving.")
           break
   filetodown.write(data)
filetodown.close()
c.send("Thank you for connecting.")
c.shutdown(2)
c.close()
s.close()
#Done :)

Client side:

import socket
s = socket.socket()
s.connect(("localhost", 5000))
filetosend = open("img.png", "rb")
data = filetosend.read(1024)
while data:
    print("Sending...")
    s.send(data)
    data = filetosend.read(1024)
filetosend.close()
s.send(b"DONE")
print("Done Sending.")
print(s.recv(1024))
s.shutdown(2)
s.close()
#Done :)
Community
  • 1
  • 1
Ahmed
  • 414
  • 4
  • 3
  • 1. filetodown.write(data) filetodown.flush() #add this to aviod file corruption 2.below code is not work for me. if data == b"DONE": print("Done Receiving.") break but, I modify below code is work. if data <1024: #your read buffer. print("Done Receiving.") break – kyc1109 Oct 06 '21 at 05:58
1

The problem is extra 13 byte which server.py receives at the start. To resolve that write "l = c.recv(1024)" twice before the while loop as below.

print "Receiving..."
l = c.recv(1024) #this receives 13 bytes which is corrupting the data
l = c.recv(1024) # Now actual data starts receiving
while (l):

This resolves the issue, tried with different format and sizes of files. If anyone knows what this starting 13 bytes refers to, please reply.

gajendra
  • 21
  • 1
0

Put file inside while True like so

while True:
     f = open('torecv.png','wb')
     c, addr = s.accept()     # Establish connection with client.
     print 'Got connection from', addr
     print "Receiving..."
     l = c.recv(1024)
     while (l):
         print "Receiving..."
         f.write(l)
         l = c.recv(1024)
     f.close()
     print "Done Receiving"
     c.send('Thank you for connecting')
     c.close()   
tweellt
  • 2,171
  • 20
  • 28
0

you may change your loop condition according to following code, when length of l is smaller than buffer size it means that it reached end of file

while (True):
    print "Receiving..."
    l = c.recv(1024)        
    f.write(l)
    if len(l) < 1024:
        break
DAkbariSE
  • 151
  • 1
  • 13
0

This is a top Google result for "send a file through a socket in Python".

The fastest way to send a file through a socket in Python is to use socket.sendfile, introduced in Python 3.5:

socket.sendfile(fileobj)

socket.sendfile uses os.sendfile (and the sendfile syscall) to perform a high-speed file copy whenever possible and falls back to socket.send otherwise.

David Foster
  • 6,931
  • 4
  • 41
  • 42