Priefy
Priefy

Reputation: 25

Sending files between client - server through TCP socket in python?

I'm trying to send and receive files through a TCP socket. When user types put abc.txt, abc.txt should be copied to the server.
When user types get def.txt, def.txt should be downloaded to the user computer. (Actually I have to implement 2 more methods - ls to list all files in the client directory and lls to list all files in the server, but I haven't done it yet.)

Here's the code

Server

import socket
import sys
HOST = 'localhost'                 
PORT = 3820

socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.bind((HOST, PORT))

socket.listen(1)
while (1):
    conn, addr = socket.accept()
    print 'New client connected ..'
    reqCommand = conn.recv(1024)
    print 'Client> %s' %(reqCommand)
    if (reqCommand == 'quit'):
        break
    #elif (reqCommand == lls):
        #list file in server directory
    else:
        string = reqCommand.split(' ', 1)   #in case of 'put' and 'get' method
        reqFile = string[1] 

        if (string[0] == 'put'):
            with open(reqFile, 'wb') as file_to_write:
                while True:
                    data = conn.recv(1024)
                    if not data:
                        break
                    file_to_write.write(data)
                    file_to_write.close()
                    break
            print 'Receive Successful'
        elif (string[0] == 'get'):
            with open(reqFile, 'rb') as file_to_send:
                for data in file_to_send:
                    conn.sendall(data)
            print 'Send Successful'
    conn.close()

socket.close()

Client

import socket
import sys

HOST = 'localhost'    #server name goes in here
PORT = 3820

def put(commandName):
    socket.send(commandName)
    string = commandName.split(' ', 1)
    inputFile = string[1]
    with open(inputFile, 'rb') as file_to_send:
        for data in file_to_send:
            socket.sendall(data)
    print 'PUT Successful'
    return 

def get(commandName):
    socket.send(commandName)
    string = commandName.split(' ', 1) 
    inputFile = string[1]
    with open(inputFile, 'wb') as file_to_write:
        while True:
            data = socket.recv(1024)
            #print data
            if not data:
                break
            print data
            file_to_write.write(data)
            file_to_write.close()
            break
    print 'GET Successful'
    return

socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.connect((HOST,PORT))

msg = raw_input('Enter your name: ')
while(1):
    print 'Instruction'
    print '"put [filename]" to send the file the server '
    print '"get [filename]" to download the file from the server '
    print '"ls" to list all files in this directory'
    print '"lls" to list all files in the server'
    print '"quit" to exit'
    sys.stdout.write ('%s> ' %msg)
    inputCommand = sys.stdin.readline().strip()
    if (inputCommand == 'quit'):
        socket.send('quit')
        break
    # elif (inputCommand == 'ls')
    # elif (inputCommand == 'lls')
    else:
        string = inputCommand.split(' ', 1)
    if (string[0] == 'put'):
        put(inputCommand)
    elif (string[0] == 'get'):
        get(inputCommand)
socket.close()

There are several problems that I couldn't fix.

  1. The program run correctly only on the first time (both 'put' and 'get' method). After that, All commands from the client can't be sent to the server.
  2. The 'get' method doesn't work for an image/photo file.

Upvotes: 1

Views: 12660

Answers (1)

Vinod Sharma
Vinod Sharma

Reputation: 883

First problem is occurring because after handling one command, server is closing the connection.

conn.close()

Second problem is occurring because you are not reading all the data from the socket in client. At the end of while loop you have a "break" statement, due to which client is closing the socket just after reading 1024 bytes. And when server tries to send data on this close socket, its results in error on the server side.

while True:
    data = socket1.recv(1024)
    # print data
    if not data:
        break
    # print data
    file_to_write.write(data)
    file_to_write.close()
    break

There are two ways to fix this first issue.

  1. Change the client so that for each command it creates a new connection & sends command to the server.
  2. Change the server to handle multiple commands over the same connection.

Following code is the changed client to demonstrate the first way to fix the first issue. It also fixes the second issue.

import socket
import sys

HOST = 'localhost'    # server name goes in here
PORT = 3820


def put(commandName):
    socket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socket1.connect((HOST, PORT))
    socket1.send(commandName)
    string = commandName.split(' ', 1)
    inputFile = string[1]
    with open(inputFile, 'rb') as file_to_send:
        for data in file_to_send:
            socket1.sendall(data)
    print 'PUT Successful'
    socket1.close()
    return


def get(commandName):
    socket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socket1.connect((HOST, PORT))
    socket1.send(commandName)
    string = commandName.split(' ', 1)
    inputFile = string[1]
    with open(inputFile, 'wb') as file_to_write:
        while True:
            data = socket1.recv(1024)
            # print data
            if not data:
                break
            # print data
            file_to_write.write(data)
    file_to_write.close()
    print 'GET Successful'
    socket1.close()
    return


msg = raw_input('Enter your name: ')
while(1):
    print 'Instruction'
    print '"put [filename]" to send the file the server '
    print '"get [filename]" to download the file from the server '
    print '"ls" to list all files in this directory'
    print '"lls" to list all files in the server'
    print '"quit" to exit'
    sys.stdout.write('%s> ' % msg)
    inputCommand = sys.stdin.readline().strip()
    if (inputCommand == 'quit'):
        socket.send('quit')
        break
    # elif (inputCommand == 'ls')
    # elif (inputCommand == 'lls')
    else:
        string = inputCommand.split(' ', 1)
        if (string[0] == 'put'):
            put(inputCommand)
        elif (string[0] == 'get'):
            get(inputCommand)

Upvotes: 2

Related Questions