Skip to content
Advertisement

Unable to transfer file using Sockets on different computers

I recently wrote a code for a file transfer in Python. Sockets connect fine when I connect them from different terminals on the same system. But the same doesn’t seem to work when I connect them from different computers which are connected over the same Wifi network. Here’s the server code:

import os 
import socket 
 
# Creating a socket 
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
sock.bind(("192.164.X.X",2222)) 
sock.listen(5) 
print("Host Name: " , sock.getsockname()) 
 
# Accepting the connection  
client , addr = sock.accept() 
 
# Getting file details 
file_name = input("File Name:") 
file_size = os.path.getsize(file_name) 
 
# Sending file name and details 
client.send(file_name.encode()) 
client.send(str(file_size).encode()) 
 
# Opening file and sending data  
with open(file_name,"rb") as file: 
    c = 0 
    while c <= file_size: 
        data = file.read(1024) 
        if not (data): 
            break 
        client.sendall(data) 
        c += len(data) 
 
 
# closing the socket 
sock.close()

Here’s my client code:

import os
import socket 

host = input("Host Name: " )
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Trying to connect to socket

sock.connect((host,2222))
print("Connected Successfully")

# send file details
file_name = sock.recv(100).decode()
file_size = sock.recv(100).decode()

with open("./rec/" + file_name , "wb") as file:
    c = 0

    while c <= int(file_size):
        data = sock.recv(1024)
        if not (data):
            break
        file.write(data)
        c += len(data)


sock.close()

When I try to connect The client From a different computer I get this error :

while c <= int(file_size):
ValueError: invalid literal for int() with base 10: '3hin'

The file I am trying to transfer has a single word ‘hi’. File transfer works correctly from different terminals on same machine. But the same doesn’t work on different computers which are connected over the same wifi network. I understand the error (trying to convert string to int) but I don’t WHY it’s happening and how to fix it.

Advertisement

Answer

Your server code is sending a single TCP packet containing the content of multiple client.send() calls. This is commonly known as “corking”, and can usually be disabled (depending on your OS) using the socket.TCP_NODELAY socket option after accepting the connection.

client, addr = sock.accept() 
client.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

This is however not guaranteed to work, and depends on your OS and OS settings.

The real solution would be to create a more robust protocol and avoid relying on data being sent in different packets. In fact, this is the only sane way of implementing any protocol based on TCP. Never rely on data being split in packets in a specific way.

Decide a fixed size for encoding and sending lengths, then do the following on the server:

  1. Send a length (of fixed size, for example 8 characters or 8 bytes, or whatever you would like) for the file name.
  2. Send the filename.
  3. Send the file size (again of fixed size).
  4. Send the file contents.

While on the client:

  1. Receive exactly 8 bytes and decode the length.
  2. Receive exactly length bytes for the filename.
  3. Receive exactly 8 bytes and decode the file size.
  4. Receive exactly size bytes for the file contents.

Most importantly, note that the .recv() method of sockets can return less than the requested amount (you seem to already know that), so whatever kind of receiving operation you need to do, you will need to accumulate data in a loop until you have received the expected amount, for example:

expected = 100
data = b''

while len(data) < expected:
    data += sock.recv(expected - len(data))
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement