Send a File Through Sockets in Python

Send a file through sockets in Python

You must put all the code from sc, address = s.accept() upto sc.close() into another loop or the server simply terminates after receiving the first file. It doesn't crash, the script is just finished.

[EDIT] Here is the revised code:

import socket
import sys
s = socket.socket()
s.bind(("localhost",9999))
s.listen(10) # Accepts up to 10 connections.

while True:
sc, address = s.accept()

print address
i=1
f = open('file_'+ str(i)+".pdf",'wb') #open in binary
i=i+1
while (True):
# receive data and write it to file
l = sc.recv(1024)
while (l):
f.write(l)
l = sc.recv(1024)
f.close()


sc.close()

s.close()

Note that s.listen(10) means "set maximum accept rate to 10 connections", not "stop after 10 connections".

Python 3: Sending files through socket. (Client-Server Program)

I've made few minimal adjustments to your code with which it runs as so that server.py continuously listens on a given port and sends back data which each invocation of client.py asks for.

server.py

#!/usr/bin/env python3
import socket
import os
import sys

def Main():
host = '127.0.0.1'
port = 50001

s = socket.socket()
s.bind((host,port))
print("server Started")
s.listen(1)
while True:
c, addr = s.accept()
print("Connection from: " + str(addr))
filename = ''
while True:
data = c.recv(1024).decode('utf-8')
if not data:
break
filename += data
print("from connected user: " + filename)
myfile = open(filename, "rb")
c.send(myfile.read())
c.close()

if __name__ == '__main__':
Main()

client.py

#!/usr/bin/env python3 
import socket, os.path, datetime, sys

def Main():
host = '127.0.0.1'
port = 50001

s = socket.socket()
s.connect((host, port))

Filename = input("Type in ur file ")
s.send(Filename.encode('utf-8'))
s.shutdown(socket.SHUT_WR)
data = s.recv(1024).decode('utf-8')
print(data)
s.close()

if __name__ == '__main__':
Main()

And now a bit of explanation.

On the server side. The outer loop accepts a connection, then reads from the connection until done (more on this later). Prints your debugging info, but note you were trying to print the file object and not the filename (which would fail trying to concatenate). I also open the file in binary mode (that way I can skip the str -> bytes translation.

On the client side. I've added closing the writing end of the socket when the file has been sent. Note you might want to use sendall instead of send for this use case: check those docs links for details. And I've added a print for the incoming data.

Now that bit with shutting down the writing end in the client and the inner loop reading (and also related to the sendall hint. Which BTW also holds true for the server side, otherwise you should loop, as you might see your content truncated; other option is to also have a sending loop.). Stream sockets will guarantee you get your bytes in in order you've send them. On itself it has no idea whether your message is complete and it also does not guarantee in how many and how large chunks will the data be sent and received (resp.).

The inner loop of server keep reading until we see an EOF (we've receive zero length string in python socket). This would happen (be returned by recv when the remote socket (or at least its writing end) has been shut down. Since we still want to reuse the connection, we only do that on the sending end in the client. Hope this helps you to move ahead.

sending file through socket in python 3

You are closing the server connection before the client read the “done”

Send big file over socket

Check the return value of send and recv. The 9000000 value is a maximum but not guaranteed value to send/recv. Alternatively, use sendall.

For recv, you have to loop until you receive all the data. If you close the socket after the file is sent, recv will return zero when all the data is received.

FYI, your while True: in both files never loops due to the break, so they are unnecessary.

Here's something that should work...

server.py

import socket

soc = socket.socket()
soc.bind(('',8080))
soc.listen(1)

print('waiting for connection...')
with soc:
con,addr = soc.accept()
print('server connected to',addr)
with con:
filename = input('enter filename to send: ')
with open(filename, 'rb') as file:
sendfile = file.read()
con.sendall(sendfile)
print('file sent')

client.py

import socket

soc = socket.socket()
soc.connect(('localhost',8080))
savefilename = input("enter file name to receive: ")
with soc,open(savefilename,'wb') as file:
while True:
recvfile = soc.recv(4096)
if not recvfile: break
file.write(recvfile)
print("File has been received.")

How to send zip file using Python sockets?

There were several issues with your code. For example, when reading the zip (binary) file, you should read it as bytes, not as string, and send it as bytes. Also, your server needs to know in advance the expected file size to be able to read the file in chunks. You can do that using byte ordering. Below is a working example. Credits go to this for the data receiving approach, which was slightly modified to read the data in chunks, as your code requires.

EDIT: The server has been modified to support reconnection from the client. Thus, client = s.accept() has been moved to inside the while loop and client's connection gets closed after the file has been received.

server.py

import sys                                           
import socket

HOST = sys.argv[1] if len(sys.argv) > 1 else '0.0.0.0'
PORT = int(sys.argv[2] if len(sys.argv) > 2 else 5555)
SIZE = 1024
BYTEORDER_LENGTH = 8
FORMAT = "utf-8"
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(1)

while True:
client = s.accept()
print(f"\033[33m[*] Listening as {HOST}:{PORT}\033[m")
print(f"\033[32m[!] Client connected {client[1]}\033[m")

print(f"Sending 'copy trash' msg")
client[0].send('copy trash'.encode())

print(f"[RECV] Receiving the file size")
file_size_in_bytes = client[0].recv(BYTEORDER_LENGTH)
file_size= int.from_bytes(file_size_in_bytes, 'big')
print("File size received:", file_size, " bytes")
client[0].send("File size received.".encode(FORMAT))

print(f"[RECV] Receiving the filename.")
filename = client[0].recv(SIZE).decode(FORMAT)
print(f"[RECV]Filename received:", filename)
client[0].send("Filename received.".encode(FORMAT))

print(f"[RECV] Receiving the file data.")
# Until we've received the expected amount of data, keep receiving
packet = b"" # Use bytes, not str, to accumulate
while len(packet) < file_size:
if(file_size - len(packet)) > SIZE: # if remaining bytes are more than the defined chunk size
buffer = client[0].recv(SIZE) # read SIZE bytes
else:
buffer = client[0].recv(file_size - len(packet)) # read remaining number of bytes

if not buffer:
raise Exception("Incomplete file received")
packet += buffer
with open(filename, 'wb') as f:
f.write(packet)

print(f"[RECV] File data received.")
client[0].send("File data received".encode(FORMAT))
client[0].close()
s.close()

client.py

import sys                                           
import socket
import subprocess
import shutil
import os

HOST = sys.argv[1] if len(sys.argv) > 1 else '127.0.0.1'
PORT = int(sys.argv[2] if len(sys.argv) > 2 else 5555)
FORMAT = "utf-8"
SIZE = 1024
BYTEORDER_LENGTH = 8
s = socket.socket()
s.connect((HOST, PORT))

msg = s.recv(SIZE).decode()
print('[*] server:', msg)

if(msg.lower() == "copy trash"):
#shutil.make_archive("/root/trashcopy", 'zip', "/root/.local/share/Trash")
shutil.make_archive("_trashcopy", 'zip', "Trash")

file_size = os.path.getsize('_trashcopy.zip')
print("File Size is :", file_size, "bytes")
file_size_in_bytes = file_size.to_bytes(BYTEORDER_LENGTH, 'big')

print("Sending the file size")
s.send(file_size_in_bytes)
msg = s.recv(SIZE).decode(FORMAT)
print(f"[SERVER]: {msg}")

print("Sending the file name")
s.send("trashcopy.zip".encode(FORMAT))
msg = s.recv(SIZE).decode(FORMAT)
print(f"[SERVER]: {msg}")

print("Sending the file data")
with open ('_trashcopy.zip','rb') as f1:
s.send(f1.read())
msg = s.recv(SIZE).decode(FORMAT)
print(f"[SERVER]: {msg}")
s.close()


Related Topics



Leave a reply



Submit