Sending a file over TCP connection - python

I want to send i file over TCP but when i try to run this the connection fails, the server receives the file but it gives this error: ERROR: Client timed out before sending a file
import selectors
import sys
from socket import *
import sock
sel1 = selectors.DefaultSelector()
print(len(sys.argv), sys.argv[1], sys.argv[2], sys.argv[3])
host = sys.argv[1]
port = int(sys.argv[2])
file = sys.argv[3]
try:
# Instaniating socket object
s = socket(AF_INET, SOCK_STREAM)
# Getting ip_address through host name
host_address = gethostbyname(host)
# Connecting through host's ip address and port number using socket object
s.connect((host_address, port))
sel1.register(
sock,
selectors.EVENT_READ, data = None)
fileToSend = open("file.txt", "rb")
data = fileToSend.read(1024)
while data:
print("Sending...")
fileToSend.close()
s.send(b"Done")
print("Done Sending")
print(s.recv(1024))
s.shutdown(2)
s.close()
except:
# Returning False in case of an exception
sys.stderr.write("Connection Failed")

Do the writing in a loop. There's no particular reason to chop it into 1024-byte pieces; the network stack will handle that for you.
By the way, your "Done" signal is not a good idea, especially since you're writing a binary file that might very well contain the word "Done". Remember that TCP is a streaming protocol. The other end does not see the exact packets you're sending. That is, just because you send 1024 bytes and 4 bytes, the other end might see it as reads of 256 and 772 bytes.
# Instaniating socket object
s = socket(AF_INET, SOCK_STREAM)
# Getting ip_address through host name
host_address = gethostbyname(host)
# Connecting through host's ip address and port number using socket object
s.connect((host_address, port))
fileToSend = open("file.txt", "rb")
print("Sending...")
while True:
data = fileToSend.read(1024)
if not data:
break
s.send( data )
fileToSend.close()
s.send(b"Done")
print("Done Sending")
print(s.recv(1024))
s.close()

Related

sending multiple files in python

I'm new with python, I am trying the following, I have two calsess: Server.py and Client.py I want to send all the files that exists in server directory to some directory at the client side. i.e
C:\ServerDir\file1.txt
C:\ServerDir\file2.txt
C:\ServerDir\file3.txt...
would go to:
D:\ClientDir\file1.txt
D:\ClientDir\file2.txt
D:\ClientDir\file3.txt...
For now I can send single file, Server.py:
import socket # Import socket module
port = 60000 # Reserve a port for your service.
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
s.bind((host, port)) # Bind to the port
s.listen(5) # Now wait for client connection.
print ('Server listening....')
while True:
conn, addr = s.accept() # Establish connection with client.
print ('Got connection from', addr)
data = conn.recv(1024)
print('Server received', repr(data))
filename='C:\\Users\\Desktop\\File.txt'
f = open(filename,'rb')
l = f.read(1024)
while (l):
conn.send(l)
print('Sent ',repr(l))
l = f.read(1024)
f.close()
print('Done sending')
conn.send('Thank you for connecting'.encode())
conn.close()
Client.py:
import socket # Import socket module
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
port = 60000 # Reserve a port for your service.
s.connect((host, port))
s.send("Hello server!".encode())
with open('C:\\Users\\Desktop\\Python\\gg.txt', 'wb') as f:
print ('file opened')
while True:
print('receiving data...')
data = s.recv(1024)
print('data=%s', (data))
if not data:
break
# write data to a file
f.write(data)
f.close()
print('Successfully get the file')
s.close()
print('connection closed')
I have tried to loop over all files in server side like:
for file in os.listdir('C:\\Users\\Desktop\\'):
filename = 'C:\\Users\\Desktop\\'+file
but it sends only the first file.
The critical bit is - how do you know a file ended? In your current implementation, if the connection ends, so does the file (and then you have a closed socket, so no chance for a next file).
There are two solutions:
Simple: Make the client open a new connection for each file (i.e. move stuff into the loop); if you get an instant broken connection, maybe that's the end of everything
Better: Have the server send the file size before the file itself. Have the client only write data to a file till the size is correct, then start working on a new file.
Of course, you still have an issue about how the server will know what file names to assign the incoming files. You could put those into the "header" that by now likely consists of filename :)
If you're wondering, this is exactly (well, close enough) what HTTP does. Each file has headers, then an empty line, then a stream of bytes whose length was communicated before by the Content-Length header. After that, the connection can be reused for the next file. If Content-Length is missing, the agent will read till the connection is broken (and the next file will need to establish a new connection).

'b' is getting passed when sending string from client to server in python while trying FTP implementation

I am trying to implement to implement FTP where I want to send Filename to server from client, I have tried below code, when I give file name as myText.txt but server is receiving as 'b"myText.txt'"
Can you please help me how can I get rid of b ?
This is the output on server:
This is server code:
import socket # Import socket module
port = 60000 # Reserve a port for your service.
socketObj = socket.socket() #Create a socket object
host = socket.gethostname() # Get local machine name
socketObj.bind((host, port)) # Bind to the port
socketObj.listen(5) # Now wait for client connectionection.
print ('Server listening....')
while True:
connection, addr = socketObj.accept() # Establish connectionection with client.
print ('Got connectionection from', addr)
data = connection.recv(1024)
print('Server received request for FTS of',(data))
filename=(repr(data))
f = open(filename,'rb')
l = f.read(1024)
while (l):
connection.send(l)
print('Sent ',repr(l))
l = f.read(1024)
f.close()
print('Done sending')
connection.send(('Thank you for connectionecting').encode())
connection.close()
This is the client code
import socket # Import socket module
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
port = 60000 # Reserve a port for your service.
s.connect((host, port))
fileNeeded = input("What File do you need, please enter the name:")
s.send(fileNeeded.encode())
fileToBeSaved = input("Enter file name to save requested file")
with open(fileToBeSaved, 'wb') as f:
print ('file opened')
while True:
print('receiving data...')
data = s.recv(1024)
print((data))
if not data:
break
# write data to a file
f.write(data)
f.close()
print('Successfully got the file')
s.close()
print('connection closed')
The following is received in server:
Server received request for FTS of b'mytext.txt'
You can use the bytes.decode() method to convert bytes into a string:
Change:
filename=(repr(data))
to:
filename=repr(data).decode()

How do you send a dictionary over a socket in Python?

I know that similar questions have been raised but they don't seem to work for me! I have tried serializing the dictionary then converting that to a string then encoding it before I send it over the socket. No success so far!
This is my server code:
#library
import socket
import pickle
#socket initialization
host = "127.0.0.1"
port = 5000
mainAddr = (host, port)
#dict initialization
dataDict = {} #just imagine that dict has content
#create socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #TCP
s.bind((mainAddr))
s.listen(4)
print('program started')
print('listening..')
while True:
try:
conn, addr = s.accept()
print("connection from: "+str(addr))
print("sending message..")
pickle.dumps(dataDict)
print('pickled!')
dataS = str(dataP)
print('stringed!')
dataE = dataS.encode('UTF-8')
print('encoded!')
s.sendto(dataE,addr)
print('data sent!')
except:
pass
s.close()
For the socket initialization, I've tried other types:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #UDP
s = socket.socket()
For the sending part, I've tried these alternatives:
s.send(dataE)
s.send(dataE,addr)
s.sendall(dataE)
s.sendall(dataE,addr)
When I run the program, these get printed out:
program started
listening..
connection from:<insert addr here>
sending message..
pickled!
stringed!
encoded!
Only data sent! is not sent. So I am guessing that it's the sending part that has a problem.
For the client side, here's the code:
#library
import socket
import pickle
#initialization
host = '127.0.0.1'
port = 5000
buffer = 1024
#create socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #TCP
s.connect((host,port))
print('connected!')
#receive dictionary
print('receiving message..')
while True:
data, addr = s.recvfrom(buffer)
print('received!')
dataD = data.decode("UTF-8")
print('decoded!')
dataP = pickle.loads(dataD)
print('unpickled!')
print(str(dataP))
s.close()
In the client terminal, only the following prints:
connected!
receiving message..
On the client side, I've tried changing the order of unpickling and decoding but still, to no avail.
A TCP server socket is not actually used for sending/receiving data; I'm surprised you're not getting an error when calling s.send() or similar on it. Instead, it's a factory for producing individual sockets for each client that connects to the server - conn, in your code. So, conn.sendall() is what you should be using. No address parameter is required, the individual socket already knows who it is talking to. (.send() is unreliable without some extra work on your part; .sendto() is only used with UDP sockets that have not been connected to a particular client.)

python video streaming display packets

I am working on a Networks course project, in which I have to create a video streaming server. I found this link for a simple python client/server socket binary stream that seems quite useful. I am able to send video files as packets over the network, but the receiving side is saving the incoming packets as a file. I would like to display the incoming packets as a video stream (preferably on a web browser using HTML), instead of writing to a file. Please suggest some possible method of doing this. Thanks.
As I am doing a project, I would like to create a streaming server from scratch rather than use existing implementations like Flumotion.
Here's the code for the sending and receiving sides:
Sending side:
import socket
HOST = 'localhost'
PORT = 9876
ADDR = (HOST,PORT)
BUFSIZE = 4096
videofile = "./test2.mp4"
bytes = open(videofile).read()
print len(bytes)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(ADDR)
client.send(bytes)
client.close()
Receiving side:
import socket
HOST = ''
PORT = 9876
ADDR = (HOST,PORT)
BUFSIZE = 4096
serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serv.bind(ADDR)
serv.listen(5)
print 'listening ...'
while True:
conn, addr = serv.accept()
print 'client connected ... ', addr
myfile = open('testfile.mov', 'w')
while True:
data = conn.recv(BUFSIZE)
if not data: break
myfile.write(data)
print 'writing file ....'
myfile.close()
print 'finished writing file'
conn.close()
print 'client disconnected'

sending/receiving file UDP in python

I've made this sending / receiving scripts but i corrupted file !
i have no idea why I'm getting this issue !
sender.py
#!/usr/bin/env python
from socket import *
import sys
s = socket(AF_INET,SOCK_DGRAM)
host =sys.argv[1]
port = 9999
buf =1024
addr = (host,port)
file_name=sys.argv[2]
f=open(file_name,"rb")
data = f.read(buf)
s.sendto(file_name,addr)
s.sendto(data,addr)
while (data):
if(s.sendto(data,addr)):
print "sending ..."
data = f.read(buf)
s.close()
f.close()
receiver.py
#!/usr/bin/env python
from socket import *
import sys
import select
host="0.0.0.0"
port = 9999
s = socket(AF_INET,SOCK_DGRAM)
s.bind((host,port))
addr = (host,port)
buf=1024
data,addr = s.recvfrom(buf)
print "Received File:",data.strip()
f = open(data.strip(),'wb')
data,addr = s.recvfrom(buf)
try:
while(data):
f.write(data)
s.settimeout(2)
data,addr = s.recvfrom(buf)
except timeout:
f.close()
s.close()
print "File Downloaded"
and this the original receiver that I've modify it (works fine 100%)
#!/usr/bin/env python
from socket import *
import sys
import select
host="0.0.0.0"
port = 9999
s = socket(AF_INET,SOCK_DGRAM)
s.bind((host,port))
addr = (host,port)
buf=1024
f = open("file.pdf",'wb')
data,addr = s.recvfrom(buf)
try:
while(data):
f.write(data)
s.settimeout(2)
data,addr = s.recvfrom(buf)
except timeout:
f.close()
s.close()
print "File Donwloaded"
as you notice it's making file at the beginning.
exacted:
client => send file (name.ext) => server:save it (name.ext)
my output :
corrupted file for pdf and empty for txt
The problem with your code:
When data is send through sockets, normally the lower layers will merge the data from multiple sendTo calls and send them together to reduce network load.
You are sending the first 1024 bytes of the file twice.
What you should do:
Use some kind of a delimiter string having couple of characters (like "**_$$") so that it won't exist in the actual file binary representation. Then append this delimiter to the end of the filename.
Read from file again before starting the while loop.
At receiver end, receive everything into a single stream and then split using the delimiter. You will have the filename and the file data.
Update:
Working Code (Ubuntu / Windows XP)
# ----- sender.py ------
#!/usr/bin/env python
from socket import *
import sys
s = socket(AF_INET,SOCK_DGRAM)
host =sys.argv[1]
port = 9999
buf =1024
addr = (host,port)
file_name=sys.argv[2]
s.sendto(file_name,addr)
f=open(file_name,"rb")
data = f.read(buf)
while (data):
if(s.sendto(data,addr)):
print "sending ..."
data = f.read(buf)
s.close()
f.close()
# ----- receiver.py -----
#!/usr/bin/env python
from socket import *
import sys
import select
host="0.0.0.0"
port = 9999
s = socket(AF_INET,SOCK_DGRAM)
s.bind((host,port))
addr = (host,port)
buf=1024
data,addr = s.recvfrom(buf)
print "Received File:",data.strip()
f = open(data.strip(),'wb')
data,addr = s.recvfrom(buf)
try:
while(data):
f.write(data)
s.settimeout(2)
data,addr = s.recvfrom(buf)
except timeout:
f.close()
s.close()
print "File Downloaded"
Usage
>> python recevier.py
>> python sender.py localhost filename.txt
There are two problems here:
Syntax errors:
You're using a from socket import *. It's not an error on its own, but it becomes one when you do except socket.timeout.
Using UDP:
Using UDP, corruption shouldn't be a surprise. You probably don't want to be using UDP here, you should switch to TCP.
Here's why UDP is not appropriate here:
Packets may be lost but others could still reach their destination.
Packets may be duplicated
Packets may arrive in the wrong order
Note that switching to TCP will involve some refactoring of your code (it's a bit more complicated that just replacing SOCK_DGRAM with SOCK_STREAM), but in your case, you have to do it.
I'm not saying UDP is bad, but it's not appropriate in your case.

Categories