[Python] Send files over the network using PyQT and sockets

DON'T post new tutorials here! Please use the "Pending Submissions" board so the staff can review them first.
Post Reply
User avatar
maboroshi
Dr. Mab
Dr. Mab
Posts: 1624
Joined: 28 Aug 2005, 16:00
18

[Python] Send files over the network using PyQT and sockets

Post by maboroshi »

Hello! Cats asked me about building a file transfer program the other day. He was going to build one in C++ and I made one in Python. Anyway here is a description of what I did to make a small File Transfer Program between two people.

import our modules

Code: Select all

import socket
import select
import sys, os
from PyQt4.QtCore import * 
from PyQt4.QtGui import *
Next we declare our command our server will receive when we begin a file transfer

Code: Select all

CMD_FILE = 1
Our global variables for connecting to the remote server (change these as needed)

Code: Select all

CLIENT_PORT = 9001
CLIENT_HOST = '127.0.0.1'
Then set up our GUI code just two buttons for connecting to the remote server

Code: Select all

class MainWindow(QWidget):

    def __init__(self, parent=None):
        #super(QWidget, self).__init__(parent)
        super(MainWindow, self).__init__(parent)
        self.resize(100, 50)
        self.thread = Worker()
        self.thread.start()

        self.file_button = QPushButton('Send a File')
        self.connect(self.file_button, SIGNAL("released()"), self.sendFile)

        self.connect_button = QPushButton('Connect To Server')
        self.connect(self.connect_button, SIGNAL("released()"), self.connectToServer)

        self.connect(self.thread, SIGNAL('triggered(PyQt_PyObject)'), self.saveFile)
        self.layout = QFormLayout()
        self.layout.addRow(self.file_button, self.connect_button)
        
        self.setLayout(self.layout)
Our connectToServer Function (self explanatory)

Code: Select all

    def connectToServer(self):
        global s
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((str(CLIENT_HOST).strip(), CLIENT_PORT))
            print "Connected to ", str(CLIENT_HOST)
        except:
            print "unable to connect"
This next function takes a command and a msg (our data) and sends it to the server

Code: Select all

    def clientAll(self, cmd, msg):
        #check if connnected send a message
        s.sendall(cmd + msg)
Send our file

Code: Select all

    def sendFile(self):
        filename=QFileDialog.getOpenFileName(self, 'Open File', '.')
        f = open(filename, 'rb')
        myFile = f.read()
        self.clientAll(chr(CMD_FILE), myFile)
        f.close()
        print filename, "Sent\n"
This next function will be called when the server receives the command sent by the sendFile function

Code: Select all


    def saveFile(self, msg):
        reply = QMessageBox.question(self, 'Message',
            "Are you sure you wish to download this file?", QMessageBox.Yes | 
            QMessageBox.No, QMessageBox.No)
        
        if reply == QMessageBox.Yes:
            filename = QFileDialog.getSaveFileName(self, 'Save File', '.')
            f = open(filename, 'wb')
            f.write(msg)
            f.close()
            print filename, "Recieved"
        else:
            pass

Our threaded server

Code: Select all

class Worker(QThread):
    
    def __init__(self):
        QThread.__init__(self)
        self.exiting = False

    def __del__(self):
        self.exiting = True
        self.wait()


    def run(self):
        source_ip = ''
        #socket.gethostbyname(socket.gethostname())
        PORT = 9001
        ### Initialize socket
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server_socket.bind((source_ip, PORT))
        # 
        server_socket.listen(5)
        read_list = [server_socket]
        ### Start receive loop
        while True:
            readable, writable, errored = select.select(read_list, [], [])
            for s in readable:
                if s is server_socket:
                    conn, addr = s.accept()
                    read_list.append(conn)
                else:
                    msg = conn.recv(12024)
                    if msg:                
                        cmd, msg = ord(msg[0]),msg[1:]
                        if cmd == CMD_FILE:
                            if not msg: break
                            self.emit(SIGNAL('triggered(PyQt_PyObject)'), msg)
                    else:
                        s.close()
                        read_list.remove(s)
Notice the CMD_FILE variable :D I am sure you can understand it

Now run our application.

Code: Select all

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MainWindow()
    win.setWindowTitle('CATS!!! <3')
    win.show()
    sys.exit(app.exec_())

and the full Python Code

Code: Select all

import socket
import select
import sys, os
from PyQt4.QtCore import * 
from PyQt4.QtGui import *

CMD_FILE = 1

CLIENT_PORT = 9001
CLIENT_HOST = '127.0.0.1'

class MainWindow(QWidget):

    def __init__(self, parent=None):
        #super(QWidget, self).__init__(parent)
        super(MainWindow, self).__init__(parent)
        self.resize(100, 50)
        self.thread = Worker()
        self.thread.start()

        self.file_button = QPushButton('Send a File')
        self.connect(self.file_button, SIGNAL("released()"), self.sendFile)

        self.connect_button = QPushButton('Connect To Server')
        self.connect(self.connect_button, SIGNAL("released()"), self.connectToServer)

        self.connect(self.thread, SIGNAL('triggered(PyQt_PyObject)'), self.saveFile)
        self.layout = QFormLayout()
        self.layout.addRow(self.file_button, self.connect_button)
        
        self.setLayout(self.layout)

    def connectToServer(self):
        global s
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((str(CLIENT_HOST).strip(), CLIENT_PORT))
            print "Connected to ", str(CLIENT_HOST)
        except:
            print "unable to connect"
       

    def clientAll(self, cmd, msg):
        #check if connnected send a message
        s.sendall(cmd + msg)


    def sendFile(self):
        filename=QFileDialog.getOpenFileName(self, 'Open File', '.')
        f = open(filename, 'rb')
        myFile = f.read()
        self.clientAll(chr(CMD_FILE), myFile)
        f.close()
        print filename, "Sent\n"

    def saveFile(self, msg):
        reply = QMessageBox.question(self, 'Message',
            "Are you sure you wish to download this file?", QMessageBox.Yes | 
            QMessageBox.No, QMessageBox.No)
        
        if reply == QMessageBox.Yes:
            filename = QFileDialog.getSaveFileName(self, 'Save File', '.')
            f = open(filename, 'wb')
            f.write(msg)
            f.close()
            print filename, "Recieved"
        else:
            pass


class Worker(QThread):
    
    def __init__(self):
        QThread.__init__(self)
        self.exiting = False

    def __del__(self):
        self.exiting = True
        self.wait()


    def run(self):
        source_ip = ''
        #socket.gethostbyname(socket.gethostname())
        PORT = 9001
        ### Initialize socket
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server_socket.bind((source_ip, PORT))
        # 
        server_socket.listen(5)
        read_list = [server_socket]
        ### Start receive loop
        while True:
            readable, writable, errored = select.select(read_list, [], [])
            for s in readable:
                if s is server_socket:
                    conn, addr = s.accept()
                    read_list.append(conn)
                else:
                    msg = conn.recv(12024)
                    if msg:                
                        cmd, msg = ord(msg[0]),msg[1:]
                        if cmd == CMD_FILE:
                            if not msg: break
                            self.emit(SIGNAL('triggered(PyQt_PyObject)'), msg)
                    else:
                        s.close()
                        read_list.remove(s)



if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MainWindow()
    win.setWindowTitle('CATS!!! <3')
    win.show()
    sys.exit(app.exec_())
Enjoy *cheers Maboroshi

User avatar
lilrofl
Siliconoclast
Siliconoclast
Posts: 1363
Joined: 28 Jan 2009, 17:00
15
Location: California, USA
Contact:

Re: [Python] Send files over the network using PyQT and sockets

Post by lilrofl »

This is great stuff Mabs, glad to see you using PyQT more, it's a fantastic framework!
knuffeltjes voor mijn knuffel
[img]http://i911.photobucket.com/albums/ac320/stuphsack/Sig.jpg[/img]

Post Reply