|
|
|||||||||
|
|||||||||
| |||||||||
|
|
|
| |||||||||
![]() |
|
|
«
Previous Thread
|
Next Thread
»
|
Thread Tools | Search this Thread | Rate Thread | Display Modes |
|
|
AT&T devCentral & BlackBerry(r) Webcast Series: BlackBerry and GPS -Build Location Awareness into your BlackBerry Applications, July 10th-1:00PM EST. Register Today!
|
|
#1
|
|||
|
|||
|
Sending a file using sockets
Does anyone know how to properly send a file using sockets? At the moment I am using this:
Code:
sock.sendall(somefile.read()) and Code:
input = sock.recv(1024) on the other end. It works for simple stuff like tiny text files (well anything under 1024 bytes) but it's obviously not going to work for something like an mp3. Am I supposed to loop my recv until I get a 0? |
|
#2
|
|||
|
|||
|
It has been a while since I have done any programming with raw sockets, but I think you are right, loop until recv returns zero. The example in the docs does exactly that.
An alternative way is to create a file-like object from the socket, and read from it exactly like you would a file. From the docs for the socket object: Quote:
Hope this helps. Dave - The Developers' Coach |
|
#3
|
||||
|
||||
|
I only know ftp:
The ftplib uses sendall for sending and the following code snippet for receiving: Code:
while 1:
data = conn.recv(blocksize)
if not data:
break
callback(data)
conn.close()
(The callback is used to write the data to a file). sendall manages the transfer - splitting the large block of data into smaller blocks and sending/resending as necessary until all is received, the data will be passed up to your higher level in the correct sequence although the order in which it is actually received may be different. FTP obviously wraps this in a protocol so that both sides of the conversation know what to expect. Before the transfer there is an exchange of commands and acknowledgements. The problem is it's dedicating the connection for file transfer. You have no clean way to interrupt it. One solution is to create a second socket connection just for file transfer (this is what ftp does) leaving the original socket for commands and other traffic Code:
From RFC 959
-------------
|/---------\|
|| User || --------
||Interface|<--->| User |
|\----^----/| --------
---------- | | |
|/------\| FTP Commands |/----V----\|
||Server|<---------------->| User ||
|| PI || FTP Replies || PI ||
|\--^---/| |\----^----/|
| | | | | |
-------- |/--V---\| Data |/----V----\| --------
| File |<--->|Server|<---------------->| User |<--->| File |
|System| || DTP || Connection || DTP || |System|
-------- |\------/| |\---------/| --------
---------- -------------
Server-FTP USER-FTP
One alternative could be to use "inband" commands. In this scenario you can do something like put an info-field at the head of every packet which states it's purpose - either a command or a file packet. The file-data block you want to send will be split into sub-blocks by you and you use send() or sendall() to send each sub-block. It becomes your job to untangle the packets and re-order the sub-blocks if necessary. This way you socket is not locked when the file transfer fails - you still keep the chat going. This assumes that your receiving socket is not being battered by a rogue file sender of course. If you wrap this concept into a virtual socket class then you might have something that is very useful. By this I mean taking one "physical" socket object and allowing 'n' virtual connections to multiplex over it. This idea is used in "tunnelling" situations where routes through firewalls are needed or you only allow secure connections like ssh. This would allow anything you like - chat, file transfer, buddy lists etc. I know my msn client cannot work through my firewall for anything other than simple chat because of the need to create additional peer to peer socket connections for the actual transfer. A solution to this would be to allow all data transfers to go via the main server but this obviusly puts extra load on the server which is why they don't do it. Anyone know other "solutions"? Grim ![]()
__________________
*** Experimental Python Markup CGI V2 *** |
|
#4
|
|||
|
|||
|
That's a cool idea Grim, I'll look into it later. Btw, thanks for both of your replys
. |
|
#5
|
||||
|
||||
|
I was playing around with sockets a few weeks ago. heres two scripts i came up with. one is the server, the other is the client. you need to run the server script then call the client script with relative file as the first argument to the script.
Code:
# USAGE: python FileSender.py [file]
import sys, socket
HOST = 'localhost'
CPORT = 9091
MPORT = 9090
FILE = sys.argv[1]
cs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cs.connect((HOST, CPORT))
cs.send("SEND " + FILE)
cs.close()
ms = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ms.connect((HOST, MPORT))
f = open(FILE, "rb")
data = f.read()
f.close()
ms.send(data)
ms.close()
Code:
# USAGE: python FileReciever.py
import socket, time, string, sys, urlparse
from threading import *
#------------------------------------------------------------------------
class StreamHandler ( Thread ):
def __init__( this ):
Thread.__init__( this )
def run(this):
this.process()
def bindmsock( this ):
this.msock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
this.msock.bind(('', 9090))
this.msock.listen(1)
print '[Media] Listening on port 9090'
def acceptmsock( this ):
this.mconn, this.maddr = this.msock.accept()
print '[Media] Got connection from', this.maddr
def bindcsock( this ):
this.csock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
this.csock.bind(('', 9091))
this.csock.listen(1)
print '[Control] Listening on port 9091'
def acceptcsock( this ):
this.cconn, this.maddr = this.csock.accept()
print '[Control] Got connection from', this.maddr
while 1:
data = this.cconn.recv(1024)
if not data: break
if data[0:4] == "SEND": this.filename = data[5:]
print '[Control] Getting ready to receive "%s"' % this.filename
break
def transfer( this ):
print '[Media] Starting media transfer for "%s"' % this.filename
f = open(this.filename,"wb")
while 1:
data = this.mconn.recv(1024)
if not data: break
f.write(data)
f.close()
print '[Media] Got "%s"' % this.filename
print '[Media] Closing media transfer for "%s"' % this.filename
def close( this ):
this.cconn.close()
this.csock.close()
this.mconn.close()
this.msock.close()
def process( this ):
while 1:
this.bindcsock()
this.acceptcsock()
this.bindmsock()
this.acceptmsock()
this.transfer()
this.close()
#------------------------------------------------------------------------
s = StreamHandler()
s.start()
|
![]() |
| Viewing: Dev Shed Forums > Programming Languages > Python Programming > Sending a file using sockets |
| Thread Tools | Search this Thread |
| Display Modes | Rate This Thread |
|
|
|
|