how to send/receive multiple data? python socket? - python

I'm trying to send/receive multiple data. Server perfectly send file's name and file's data. problem is in client. I have created a two variable named filename and filedata. filename variable received filename with file's data. filedata received nothing because filename received all filename and filedata. I don't know why filename received filename+data? how do i fix that problem?
here is my code:
server.py
import socket
def send():
host = 'localhost'
port = 9999
address = (host, port)
sock = socket.socket()
sock.bind(address)
sock.listen(5)
print('listining for connection...')
con,addr = sock.accept()
print('Got connection from',addr)
file1name = 'file1.txt'
con.send(file1name.encode('utf-8'))
file1data = 'this is file 1'
con.send(file1data.encode('utf-8'))
file2name = 'file2.txt'
con.send(file2name.encode('utf-8'))
file2data = 'this is file 2'
con.send(file2data.encode('utf-8'))
con.close()
sock.shutdown(1)
sock.close()
print('connection closed!')
send()
client.py
import socket
host = 'localhost'
port = 9999
address = (host, port)
sock = socket.socket()
sock.connect(address)
print('connected to', address)
while True:
filename = sock.recv(60).decode('utf-8')
if not filename:
break
print('filename -', filename)
data = sock.recv(60).decode('utf-8')
print('data -', data)
sock.shutdown(1)
sock.close()
output server.py
listining for connection...
Got connection from ('127.0.0.1', 36886)
connection closed!
output client.py
connected to ('localhost', 9999)
filename - file1.txtthis is file 1file2.txtthis is file 2
data -

The main problem is that you have to send the data size to the client before it start to receive.
I assume the server send an unsigned int 32bit(4byte) to represent the size.
See soc.recv(4) in client.py
server.py
from socket import *
import os
import ctypes
HOST = 'localhost'
PORT = 9999
ADDRESS = (HOST, PORT)
BUF_SIZE = 1024
PATH = './uploads'
soc = socket(AF_INET, SOCK_STREAM)
soc.bind(ADDRESS)
soc.listen(5)
print('listen for connection...')
con,addr = soc.accept()
print('got connection from', addr)
print('-------------------------')
def sendFile(socket, path):
filename = os.path.basename(path)
filename_bytes = filename.encode('utf-8')
filename_size = ctypes.c_uint32(len(filename_bytes))
file_size = ctypes.c_uint32(os.stat(path).st_size)
socket.send(bytes(filename_size)) # send uint32 (4 bytes)
socket.send(filename_bytes)
socket.send(bytes(file_size)) # send uint32 (4 bytes)
with open(path, 'rb') as f:
filecontent = f.read(BUF_SIZE)
while filecontent:
socket.send(filecontent)
filecontent = f.read(BUF_SIZE)
files = os.listdir(PATH)
num_files = ctypes.c_uint32(len(files))
con.send(bytes(num_files))
for file in files:
sendFile(con, os.path.join(PATH, file))
client.py
from socket import *
import os
import ctypes
HOST = 'localhost'
PORT = 9999
ADDRESS = (HOST, PORT)
BUF_SIZE = 1024
PATH = './downloads'
soc = socket(AF_INET, SOCK_STREAM)
soc.connect(ADDRESS)
print('connected to', ADDRESS)
def recvFile(socket):
tmp = soc.recv(4)
filename_size = int.from_bytes(tmp, byteorder='little')
print('filename_size =', filename_size)
filename = soc.recv(filename_size).decode('utf-8')
print('filename =', filename)
tmp = soc.recv(4)
file_size = int.from_bytes(tmp, byteorder='little')
print('file_size =', file_size)
with open(os.path.join(PATH, filename), 'wb') as f:
while file_size > 0:
filecontent = soc.recv(min(BUF_SIZE, file_size))
f.write(filecontent)
file_size -= len(filecontent)
print('data recvd')
tmp = soc.recv(4)
num_files = int.from_bytes(tmp, byteorder='little')
for i in range(num_files):
print('{}/{}'.format(i+1, num_files))
recvFile(soc)
soc.shutdown(SHUT_RDWR)
soc.close()
print('socket closed')

Related

How can I speed-up the file transfer process between 2 computers on python?

I created a code that transfers files from the server to the client(my computer). The problem is that if I try to transfer a large file <40mb, the download speed suddenly goes down from 3mb/s to 500 bytes. Download Speed.
Here's the server and client code I currently use:
Client:
#Reciever
import socket
import os
import tqdm
SERVER_HOST = "0.0.0.0"
SERVER_PORT = 7789
BUFFER_SIZE = 4096
SEPARATOR = "<SEPARATOR>"
s = socket.socket()
s.bind((SERVER_HOST, SERVER_PORT))
s.listen(5)
print(f"[*] Listening as {SERVER_HOST}:{SERVER_PORT}")
client_socket, address = s.accept()
print(f"[+] {address} is connected")
recieved = client_socket.recv(BUFFER_SIZE).decode()
filename, filesize = recieved.split(SEPARATOR)
filename = os.path.basename(filename)
filesize = int(filesize)
progress = tqdm.tqdm(range(filesize), f"Recieving {filename}", unit = "B", unit_scale = True, unit_divisor=1024)
with open(filename, "wb") as f:
while True:
bytes_read = client_socket.recv(BUFFER_SIZE)
if not bytes_read:
break
f.write(bytes_read)
progress.update(len(bytes_read))
client_socket.close()
s.close()
Server:
#Sender
import socket
import tqdm
import os
SEPARATOR = "<SEPARATOR>"
BUFFER_SIZE = 4096
host = "192.168.0.9"
port = 7789
for files in os.listdir():
filename = files
filesize = os.path.getsize(filename)
s = socket.socket()
print(f"[+] Connecting to {host}:{port}")
s.connect((host,port))
print("[+] Connected")
s.send(f"{filename}{SEPARATOR}{filesize}").encode()
progress = tqdm.tqdm(range(filesize), f"Sending {filename}", unit="B", unit_scale=True, unit_divisor=1024)
with open(filename, "rb") as f:
while True:
bytes_read = f.read(BUFFER_SIZE)
if not bytes_read:
break
s.sendall(bytes_read)
progress.update(len(bytes_read))
s.close()

TCP transfer files without closing socket

I coded a simple TCP server - client file sharing but it only work when the script close the socket in the client side.
I tried to remove the s.close inside the client python script and it gave me an error. Any idea?
I dont know if it even possible to do this kind of things with TCP without closing socket.
here is my code
server.py
import socket
import tqdm
import os
SERVER_HOST = "192.168.1.48"
SERVER_PORT = 5001
BUFFER_SIZE = 4096
SEPARATOR = "<SEPARATOR>"
s = socket.socket()
s.bind((SERVER_HOST, SERVER_PORT))
s.listen(5)
print(f"[*] Listening as {SERVER_HOST}:{SERVER_PORT}")
client_socket, address = s.accept()
print(f"[+] {address} is connected.")
def receive_file(filename):
received = client_socket.recv(BUFFER_SIZE).decode()
filename, filesize = received.split(SEPARATOR)
filename = os.path.basename(filename)
filesize = int(filesize)
progress = tqdm.tqdm(range(filesize), f"Receiving {filename}", unit="B", unit_scale=True, unit_divisor=1024)
with open(filename, "wb") as f:
while True:
# read 1024 bytes from the socket (receive)
bytes_read = client_socket.recv(BUFFER_SIZE)
if not bytes_read:
# nothing is received
# file transmitting is done
break
# write to the file the bytes we just received
f.write(bytes_read)
# update the progress bar
progress.update(len(bytes_read))
while True:
command = input("-->")
client_socket.send(str.encode(command))
filename = command[9:]
receive_file(filename)
client.py
import socket
import tqdm
import os
SEPARATOR = "<SEPARATOR>"
BUFFER_SIZE = 4096 # send 4096 bytes each time step
host = "192.168.1.48"
port = 5001
filesize = os.path.getsize(filename)
s = socket.socket()
print(f"[+] Connecting to {host}:{port}")
s.connect((host, port))
print("[+] Connected.")
def send_file(filename,filesize):
s.send(f"{filename}{SEPARATOR}{filesize}".encode())
progress = tqdm.tqdm(range(filesize), f"Sending {filename}", unit="B", unit_scale=True, unit_divisor=1024)
with open(filename, "rb") as f:
while True:
bytes_read = f.read(BUFFER_SIZE)
if not bytes_read:
# file transmitting is done
break
s.sendall(bytes_read)
progress.update(len(bytes_read))
# close the socket
s.close()
while True:
command = s.recv(4096)
if command[:8].decode("utf-8") == "download":
print("yes it start")
filename = command[9:].decode("utf-8")
print(filename)
filesize = os.path.getsize(filename)
send_file(filename,filesize)
Break out of the loop when you've received filesize bytes.
with open(filename, "wb") as f:
total_bytes = 0
while total_bytes < filesize:
# read 1024 bytes from the socket (receive)
bytes_read = client_socket.recv(BUFFER_SIZE)
if not bytes_read:
# nothing is received
# file transmitting is done
break
# write to the file the bytes we just received
f.write(bytes_read)
total_bytes += len(bytes_read)
# update the progress bar
progress.update(len(bytes_read))

Sending Multiple Files Python Using Socket

I currently am trying to create a client-server application in which the client can send multiple files to the server using TCP protocol. The server will eventually create a hash-algorithm and send it back to the client but I am running into issues sending multiple files from the client to the server. In it's current form, the first file sends correctly but the files after encounter an error where the information is merged together. IE the file size is listed as the second file's name. I am a javascript dude and very new to python so an explanation to how I can make this happen would be much appreciated. I believe threading is the answer but with my limited understanding of python, I do not know how to make this work. Currently I can send one file at a time and the server stays open. However, I would like to enter several file names from my current directory and have them processed. I eventually will convert the entire client side into C but I am struggling to get the server to work correctly in python. Any advice would be much appreciated!
Server.py
import socket
import hashlib
import threading
import struct
HOST = '127.0.0.1'
PORT = 2345
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(10)
print("Waiting for a connection.....")
conn, addr = s.accept()
print("Got a connection from ", addr)
while True:
hash_type = conn.recv(1024)
print('hash type: ', hash_type)
if not hash_type:
break
file_name = conn.recv(1024)
print('file name: ', file_name)
file_size = conn.recv(1024)
file_size = int(file_size, 2)
print('file size: ', file_size )
f = open(file_name, 'wb')
chunk_size = 4096
while file_size > 0:
if file_size < chunk_size:
chuk_size = file_size
data = conn.recv(chunk_size)
f.write(data)
file_size -= len(data)
f.close()
print('File received successfully')
s.close()
Client.py
import socket
import threading
import os
HOST = '127.0.0.1'
PORT = 2345
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
hash_type = input('Enter hash type: ')
files = input('Enter file(s) to send: ')
files_to_send = files.split()
for file_name in files_to_send:
s.send(hash_type.encode())
print(file_name)
s.send(file_name.encode())
file_size = os.path.getsize(file_name)
file_size = bin(file_size)
print(file_size)
s.send(file_size.encode())
f = open(file_name, 'rb')
l = f.read()
while(l):
s.send(l)
l = f.read()
f.close()
print('File Sent')
s.close()
One way to handle what you're doing is to buffer your socket data. Below is a class that buffers data and knows how to send and receive null-terminated, UTF-8-encoded strings, and raw chunks of bytes:
buffer.py:
class Buffer:
def __init__(self,s):
'''Buffer a pre-created socket.
'''
self.sock = s
self.buffer = b''
def get_bytes(self,n):
'''Read exactly n bytes from the buffered socket.
Return remaining buffer if <n bytes remain and socket closes.
'''
while len(self.buffer) < n:
data = self.sock.recv(1024)
if not data:
data = self.buffer
self.buffer = b''
return data
self.buffer += data
# split off the message bytes from the buffer.
data,self.buffer = self.buffer[:n],self.buffer[n:]
return data
def put_bytes(self,data):
self.sock.sendall(data)
def get_utf8(self):
'''Read a null-terminated UTF8 data string and decode it.
Return an empty string if the socket closes before receiving a null.
'''
while b'\x00' not in self.buffer:
data = self.sock.recv(1024)
if not data:
return ''
self.buffer += data
# split off the string from the buffer.
data,_,self.buffer = self.buffer.partition(b'\x00')
return data.decode()
def put_utf8(self,s):
if '\x00' in s:
raise ValueError('string contains delimiter(null)')
self.sock.sendall(s.encode() + b'\x00')
With this class, your client and server become:
client.py:
import socket
import threading
import os
import buffer
HOST = '127.0.0.1'
PORT = 2345
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
with s:
sbuf = buffer.Buffer(s)
hash_type = input('Enter hash type: ')
files = input('Enter file(s) to send: ')
files_to_send = files.split()
for file_name in files_to_send:
print(file_name)
sbuf.put_utf8(hash_type)
sbuf.put_utf8(file_name)
file_size = os.path.getsize(file_name)
sbuf.put_utf8(str(file_size))
with open(file_name, 'rb') as f:
sbuf.put_bytes(f.read())
print('File Sent')
server.py:
import socket
import os
import buffer
HOST = ''
PORT = 2345
# If server and client run in same local directory,
# need a separate place to store the uploads.
try:
os.mkdir('uploads')
except FileExistsError:
pass
s = socket.socket()
s.bind((HOST, PORT))
s.listen(10)
print("Waiting for a connection.....")
while True:
conn, addr = s.accept()
print("Got a connection from ", addr)
connbuf = buffer.Buffer(conn)
while True:
hash_type = connbuf.get_utf8()
if not hash_type:
break
print('hash type: ', hash_type)
file_name = connbuf.get_utf8()
if not file_name:
break
file_name = os.path.join('uploads',file_name)
print('file name: ', file_name)
file_size = int(connbuf.get_utf8())
print('file size: ', file_size )
with open(file_name, 'wb') as f:
remaining = file_size
while remaining:
chunk_size = 4096 if remaining >= 4096 else remaining
chunk = connbuf.get_bytes(chunk_size)
if not chunk: break
f.write(chunk)
remaining -= len(chunk)
if remaining:
print('File incomplete. Missing',remaining,'bytes.')
else:
print('File received successfully.')
print('Connection closed.')
conn.close()
Demo
client:
Enter hash type: abc
Enter file(s) to send: demo1.dat demo2.dat
demo1.dat
File Sent
demo2.dat
File Sent
server:
Waiting for a connection.....
Got a connection from ('127.0.0.1', 22126)
hash type: abc
file name: uploads\demo1.dat
file size: 488892
File received successfully.
hash type: abc
file name: uploads\demo2.dat
file size: 212992
File received successfully.
Connection closed.
1.
file_size = conn.recv(1024)
In your server code you read 1024 bytes as your file_size, file_size is only 4 or 8 bytes long
2.
file_name = conn.recv(1024) Your server don't know how long the filename/hashtype is.
-> Use a long for both sizes and read only sizeof(long) bytes from the stream.
You can use https://docs.python.org/2/library/struct.html for packing/encoding of these numbers
-> Or just go the easy way and use https://docs.python.org/3/library/pickle.html for serialization

Socket programming client send and receive file at same time

I am trying this scenario:
Client sends file to server
Server updates on file and save it
Sends updated file back to client
Steps 1 and 2 are done correctly as I wanted but when client finishes sending the socket closes. I've tried this code but its not working. Any suggestions?
Client:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
H = socket.gethostname()
P = 1111
s.connect((H,P))
with open('File.txt', 'rb') as fileName:
for data in fileName:
s.sendall(data)
with open('ReFile.txt', 'wb') as File:
while True:
data = s.recv(1024)
print data
if not data:
break
File.write(data)
File.close()
Server:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
H= socket.gethostname()
P = 1111
s.bind((H, P))
s.listen(6)
c, address = s.accept()
print 'Connection with ' , address
with open('ReFile.txt', 'wb') as RecFile:
while True:
data = c.recv(1024)
print data
if not data:
break
RecFile.write(data)
RecFile.write("updated version")
RecFile.close()
with open('ReFile.txt', 'rb') as file:
for data in file:
s.sendall(data)
s.close()
Try this:
Server:
import socket
s = socket.socket()
H = socket.gethostname()
P = 1111
s.bind((H, P))
s.listen(6)
c, address = s.accept()
print 'Connection with ', address
lenF = int(c.recv(1024))
if lenF != 0:
c.sendall('Send data')
data = c.recv(lenF)
data += "\nUpdated Version"
RecFile = open('ReFile.txt','w')
RecFile.write(str(data))
RecFile.close()
fileN = open('ReFile.txt')
data = fileN.read(-1)
fileN.close()
lenF = len(data)
c.send(str(lenF))
if c.recv(5) == 'Ready':
c.send(data)
Here I am using lenF variable to get the size of file that I am getting from the client.
Client:
import socket
s = socket.socket()
H = socket.gethostname()
P = 1111
s.connect((H,P))
fileName = open('file.txt')
data = fileName.read(-1)
fileName.close()
dataL = int(len(data))
s.send(str(dataL))
validCheck = s.recv(9)
if validCheck == 'Send data':
print 'Sending file.......'
s.send(data)
dataL = int(s.recv(1024))
if dataL != 0:
s.send('Ready')
data = s.recv(dataL)
File = open('ReFile.txt','w')
File.write(data)
File.close()
Here I am using dataL variable to receive data length(file) and sending it.

audio over python tcp error

I am writing a simple python tcp code to send over a wav file however I seem to be getting stuck. can someone explain why my code is not working correctly?
Server Code
import socket, time
import scipy.io.wavfile
import numpy as np
def Main():
host = ''
port = 3333
MAX = 65535
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,port))
s.listen(1)
print "Listening on port..." + str(port)
c, addr = s.accept()
print "Connection from: " + str(addr)
wavFile = np.array([],dtype='int16')
i = 0
while True:
data = c.recvfrom(MAX)
if not data:
break
# print ++i
# wavfile = np.append(wavfile,data)
print data
timestr = time.strftime("%y%m%d-%h%m%s")
print timestr
# wavF = open(timestr + ".wav", "rw+")
scipy.io.wavfile.write(timestr + ".wav",44100, data)
c.close()
if __name__ == '__main__':
Main()
Client Code
host, port = "", 3333
import sys , socket
import scipy.io.wavfile
# create a tcp/ip socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect the socket to the port where the server is listening
server_address = (host, port)
print >>sys.stderr, 'connecting to %s port %s' % server_address
input_data = scipy.io.wavfile.read('Voice 005.wav',)
audio = input_data[1]
sock.connect(server_address)
print 'have connected'
try:
# send data
sock.sendall(audio)
print "sent" + str(audio)
sock.close()
except:
print('something failed sending data')
finally:
print >>sys.stderr, 'closing socket'
print "done sending"
sock.close()
Please help someone, I want to send an audio file to my embedded device with tcp since it crucial data to be processed on the embedded device.
Not sure why you go to the trouble of using scipy and numpy for this, since you can just use the array module to create binary arrays that will hold the wave file. Can you adapt and use the simple client/server example below?
(Note: I've copy/pasted a small Windows sound file called 'tada.wav' to the same folder to use with the test scripts.)
Code for the server script:
import socket
HOST = '' # Symbolic name meaning all available interfaces
PORT = 50007 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
print('Listening...')
conn, addr = s.accept()
print('Connected by', addr)
outfile = open("newfile.wav", 'ab')
while True:
data = conn.recv(1024)
if not data: break
outfile.write(data)
conn.close()
outfile.close()
print ("Completed.")
Code for the client:
from array import array
from os import stat
import socket
arr = array('B') # create binary array to hold the wave file
result = stat("tada.wav") # sample file is in the same folder
f = open("tada.wav", 'rb')
arr.fromfile(f, result.st_size) # using file size as the array length
print("Length of data: " + str(len(arr)))
HOST = 'localhost'
PORT = 50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send(arr)
print('Finished sending...')
s.close()
print('done.')
This works for me (though only tested by running both on localhost) and I end up with a second wave file that's an exact copy of the one sent by the client through the socket.

Categories