Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python socket file transfer

I'm trying to write transfer files or chunks of data over a socket. I feel as if I'm reinventing the wheel, but my searches for a simple solution have failed (everything I find is either too simple or too complex). The server would run on a phone running python 2.5.4. The intended application would be to sync music files between the phone and a host computer.

This is the guts of what I have, which appears to work. I send and receive 'ok' to break up streams.

Is sending 'ok' back and forth essentially as stop bits to break up streams of data a reasonable technique?

Is there a standard way to do this?

Running any sort of library server (ftp, http) on the phone is not a useful solution given the limits of the phone's memory and processing power.

server:

import socket

c = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
c.bind(('', 1234))
c.listen(1)
s,a = c.accept()

while True:
    data = s.recv(1024)
    cmd = data[:data.find('\n')]

    if cmd == 'get':
        x, file_name, x = data.split('\n', 2)
        s.sendall('ok')
        with open(file_name, 'rb') as f:
            data = f.read()
        s.sendall('%16d' % len(data))
        s.sendall(data)
        s.recv(2)

    if cmd == 'end':
        s.close()
        c.close()
        break

client:

import socket

s = socket.socket()
s.connect(('192.168.1.2', 1234))

def get_file(s, file_name):
    cmd = 'get\n%s\n' % (file_name)
    s.sendall(cmd)
    r = s.recv(2)
    size = int(s.recv(16))
    recvd = ''
    while size > len(recvd):
        data = s.recv(1024)
        if not data: 
            break
        recvd += data
    s.sendall('ok')
    return recvd

print get_file(s, 'file1')
print get_file(s, 'file2')
s.sendall('end\n')
like image 633
foosion Avatar asked Jul 26 '11 21:07

foosion


4 Answers

Is sending 'ok' back and forth essentially as stop bits to break up streams of data a reasonable technique?

Most protocols use some terminator or another. Popular alternatives are '\r\n', '\r\n\r\n' or EOF (ctrl+d), but these are just arbitrarily chosen and no worse or better than your 'ok', as long as your client and server know how to handle it.

like image 179
Hyperboreus Avatar answered Nov 18 '22 02:11

Hyperboreus


Your code looks good.

You don't actually need to send across the size of the file. You can use while True, as the check if not data: break will stop the loop.

while True:
    data = s.recv(1024)

    if not data: print " Done "; break

    recvd += data

Also, why are you sending 'ok' is the other side doesn't check for it? You are just skipping 2 bytes at each side.

Don't you need to cater to multiple clients? No need for multi-threading?

like image 30
ATOzTOA Avatar answered Nov 18 '22 03:11

ATOzTOA


Is there a standard way to do this?

Yes. http://www.faqs.org/rfcs/rfc959.html

Describes the standard way to do this.

Here is an implementation: http://docs.python.org/library/ftplib.html

like image 1
S.Lott Avatar answered Nov 18 '22 01:11

S.Lott


U may look at this implementation. It also take care of if the file is in a sub-directory. Here is the link!

server

import socket
import os

print('Waiting for clinet to connect...')
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.bind(('', 1234))
c.listen(1)
s, a = c.accept()

print('Connected. Going to receive file.')
s.sendall('getfilename')
filename = s.recv(1024)
if '/' in filename:
    dir = os.path.dirname(filename)
    try:
        os.stat(dir)
    except:
        print('Directory does not exist. Creating directory.')
        os.mkdir(dir)
f = open(filename, 'wb')
print('Filename: ' + filename)

while True:
    s.sendall('getfile')
    size = int(s.recv(16))
    print('Total size: ' + str(size))
    recvd = ''
    while size > len(recvd):
        data = s.recv(1024)
        if not data: 
            break
        recvd += data
        f.write(data)
        #print(len(recvd))
    break
s.sendall('end')
print('File received.')

s.close()
c.close()
f.close()

client

import socket
import sys

if len(sys.argv) > 1 :
    print('Trying to connect...')
    s = socket.socket()
    s.connect(('127.0.0.1', 1234))

    print('Connected. Wating for command.')
    while True:
        cmd = s.recv(32)

        if cmd == 'getfilename':
            print('"getfilename" command received.')
            s.sendall(sys.argv[1])

        if cmd == 'getfile':
            print('"getfile" command received. Going to send file.')
            with open(sys.argv[1], 'rb') as f:
                data = f.read()
            s.sendall('%16d' % len(data))
            s.sendall(data)
            print('File transmission done.')

        if cmd == 'end':
            print('"end" command received. Teminate.')
            break
like image 1
HiroshiFuu Avatar answered Nov 18 '22 02:11

HiroshiFuu