How To Transfer Files on a Network Using Sockets - Python

In this tutorial we'll be writing a server and client python scripts for receiving and sending files in the network using the socket module in python.
A socket is one endpoint of communication link between systems. Applications that uses network sends and receives all of its network data using socket.
In this tutorial we'll first create a server that listens for connection on a specific port number, since server is meant to serve, our server will be sending (transferring) the file to the connected client. Then next we'll create a client that'll connect to the server's host(or ip address) on the port it's listening on, then we'll recieve this file.
First we're gonna install the tqdm library that allows us to display progress, install it using:


  


pip3 install tqdm

Server

Let's start coding the server.


  


import os
import socket
import tqdm

# the size of buffer to send each at a time
buffer_size = 4096

# the file to send a client connected
file_name = 'file.html'

# get the size of the file(we'll be used for displaying progress)
file_size = os.path.getsize(file_name)

# to seperate between file name and file size
seperator = "\r\n\r\n"

From the above code, the buffer_size variable represents the size of buffer we'll be seding each at a time. Since we'll also be sending the file name and size to the client, we'll be using a seperator to seperate between the file name and file size.


  


# our device ip address
host = '0.0.0.0'

# the port number to listen on
port = 4444

You can see we set the host to 0.0.0.0 which means we want our OS(Operating System) to choose any interface available on our device. Next we create the server socket


  


print("++[*] Starting server...")
# create the server socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

The socket() method is used to creating a socket.
The socket.AF_INET means we want our socket to use IPv4 address
The socket.SOCK_STREAM mean that we want our socket to use the TCP(transmission control protocol).
Normally when you create a socket, you need to associate it with a host and port number, which we're about to do now!


  


# bind the server socket to the host and port number
try:
    server_socket.bind((host, port))
except socket.error as err:
    print(f"--[*] Failed to bind socket {err}")
    exit()

# start listening for incoming connections
server_socket.listen(10)
print(f"++[*] Server started listening on {host}:{port}")

Now our server has reached the stage of listening for connection, the listen() method of socket puts a socket in a listening mode.
Next is to accept any incoming connections.


  


# accept() returns a new socekt for the session and the client address
# we store that in a varaible
client_socket, client_addr = server_socket.accept()
print(f"++[*] Got a new connection from: {str(client_addr)}")

# send the file info immediately
client_socket.send(f"{file_name}{seperator}{file_size}".encode())

Now the last step, sending the file to the client.


  


# start sending the file to the connected client
progress = tqdm.tqdm(range(file_size), f"Seding {file_name}", unit="B", unit_scale=True, unit_divisor=1024)
with open(file_name, "rb") as file:
    while True:

        # read bytes from the file
        bytes_read = file.read(buffer_size)

        if not bytes_read:
            # finish reading the file
            break

        # send the bytes to the connected client socket
        client_socket.send(bytes_read)

        # update the progress bar
        progress.update(len(bytes_read))
        # close the client socket
        client_socket.close()
        break

# close the server socket
server_socket.close()

Now our server is ready, next we create the client.

Client

Let's start coding the client. We first initialize some varaibles


  


import os
import socket
import tqdm

# ip address to connect to
host = '127.0.0.1'

# the port number that the host is listening on
port = 4444

seperator = '\r\n\r\n'
buffer_size = 4096

You can see we set the host to 127.0.0.1(localhost) because we're using our device to taste, if you're using two different devices, you must specify the IP(internet protocol) address of that device. And we set port to 4444 because it's port number our server is listening on. Next we create the client socket and connect to the server.


  


# create a socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print(f'++[$] Connecting {host}:{port}...')

try:
    # connect to the host
    client_socket.connect((host, port))
except socket.error as err:
    print(f'--[$] Failed to connect, {err}')
    exit()

print('++[$] Connected')

By now you should be familiar with the socket.socket() function. Next we used the connect() method to connect to server, as you can see we passed in the host and port as a parameter.
Next we recieve the file info(file name and size)


  


# recieve the file info first
data = client_socket.recv(buffer_size).decode()

# get the file name and size
file_name, file_size = data.split(seperator)

# remove the absolute path if contained
file_name = os.path.basename(file_name)

# convert file_size to integer
file_size = int(file_size)

Now you've seen the use of the seperator variable, we used the split() method to seperate the string based on the seperator.
Next we need to receive the file.


  


# start receiving and saving the file
progress = tqdm.tqdm(range(file_size), f"Receiving {file_name}", unit="B", unit_scale=True, unit_divisor=1024)
with open(file_name, "wb") as file:

    while True:
        # read bytes
        bytes_read = client_socket.recv(buffer_size)

        if not bytes_read:
            # finished receiving data
            break

        # write bytes to file
        file.write(bytes_read)

        # update the progress bar
        progress.update(len(bytes_read))

# close the socket
client_socket.close()

And that was it, our client is done!.
This what I get after running the server and client:

Server:

Client:


Full Server Code:


  


import os
import socket
import tqdm

# the size of buffer to send each at a time
buffer_size = 4096

# the file to send a client connected
file_name = 'file.html'

# get the size of the file(we'll be used for displaying progress)
file_size = os.path.getsize(file_name)

# to seperate between file name and file size
seperator = "\r\n\r\n"

# our device ip address
host = '0.0.0.0'

# the port number to listen on
port = 4444

print("++[*] Starting server...")
# create the server socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# bind the server socket to the host and port number
try:
    server_socket.bind((host, port))
except socket.error as err:
    print(f"--[*] Failed to bind socket {err}")
    exit()

# start listening for incoming connections
server_socket.listen(10)
print(f"++[*] Server started listening on {host}:{port}")

# accept() returns a new socekt for the session and the client address
# we store that in a varaible
client_socket, client_addr = server_socket.accept()
print(f"++[*] Got a new connection from: {str(client_addr)}")

# send the file info immediately
client_socket.send(f"{file_name}{seperator}{file_size}".encode())

# start sending the file to the connected client
progress = tqdm.tqdm(range(file_size), f"Seding {file_name}", unit="B", unit_scale=True, unit_divisor=1024)
with open(file_name, "rb") as file:
    while True:

        # read bytes from the file
        bytes_read = file.read(buffer_size)

        if not bytes_read:
            # finish reading the file
            break

        # send the bytes to the connected client socket
        client_socket.send(bytes_read)

        # update the progress bar
        progress.update(len(bytes_read))
        # close the client socket
        client_socket.close()
        break

# close the server socket
server_socket.close()


Full Client Code:


  


import os
import socket
import tqdm

# ip address to connect to
host = '127.0.0.1'

# the port number that the host is listening on
port = 4444

seperator = '\r\n\r\n'
buffer_size = 4096

# create a socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print(f'++[$] Connecting {host}:{port}...')

try:
    # connect to the host
    client_socket.connect((host, port))
except socket.error as err:
    print(f'--[$] Failed to connect, {err}')
    exit()

print('++[$] Connected')
# recieve the file info first
data = client_socket.recv(buffer_size).decode()

# get the file name and size
file_name, file_size = data.split(seperator)

# remove the absolute path if contained
file_name = os.path.basename(file_name)

# convert file_size to integer
file_size = int(file_size)

# start receiving and saving the file
progress = tqdm.tqdm(range(file_size), f"Receiving {file_name}", unit="B", unit_scale=True, unit_divisor=1024)
with open(file_name, "wb") as file:

    while True:
        # read bytes
        bytes_read = client_socket.recv(buffer_size)

        if not bytes_read:
            # finished receiving data
            break

        # write bytes to file
        file.write(bytes_read)

        # update the progress bar
        progress.update(len(bytes_read))

# close the socket
client_socket.close()