Python Socket-Based File Transfer System with Separate Command and Data Channels

This article describes a Python project that implements a socket‑based file and folder transfer system using separate command and data threads, explains its design principles, provides the core FileFinder code, and shows how to run the server and client on Linux hosts.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Python Socket-Based File Transfer System with Separate Command and Data Channels

During recent Python studies the author explored socket programming and created a simple file‑transfer utility for Linux servers that natively support Python.

The project, hosted at GitHub , demonstrates sending files from a local host to a remote server.

Principle : The system relies on standard TCP sockets. While transferring a single file is straightforward, handling multiple files or entire directories requires a more sophisticated approach. The author introduced two separate socket channels—one for data and another for control commands—by creating distinct command thread and data thread components.

To transfer a whole folder, the program first traverses the directory structure, then sends each file sequentially over the data socket. A custom FileFinder class (blocking type) is used to enumerate files and directories, allowing the caller to pause the traversal until the previous file transfer completes.

Key source code (FileFinder):

import os,time
# 文件、文件夹寻找类 (阻塞型)
# 阻塞的设计:为了等待调用者的耗时操作【否则很快就完成了文件的遍历任务,调用者达不到顺序操作文件(夹)的意图】
class FileFinder:
   def __init__(self, finderCallback):
       self.finderCallback = finderCallback
       # 文件(夹)路径下所有文件的总大小
       self.sum_size = 0
       # 调用者控制的参数,若为False,则遍历工作继续进行,若为True,则阻塞任务,等待调用者完成它的其他耗时操作后在考虑是否改变此值
       self.recycle = True
       # 调用者控制的参数,若为False,则正常工作,若为True,则当recycle为False时遍历工作不阻塞快速完成,recycle为True时遍历工作阻塞
       self.off = False

   # 文件(夹)找到时的回调类
   class FinderCallback:
       # 找到文件夹
       def onFindDir(self, dir_path):
           pass
       # 找到文件
       def onFindFile(self, file_path, size):
           pass
       # 预留的刷新函数
       def onRefresh(self):
           pass

   # 查找文件(夹)方法
   def list_flie(self, root_dir):
       if os.path.isfile(root_dir):
           while self.recycle:
               time.sleep(0.05)
           if self.finderCallback:
               self.finderCallback.onFindFile(root_dir, os.path.getsize(root_dir))
               self.finderCallback.onRefresh()
               if not self.off:
                   self.recycle = True
       else:
           dirlist = os.listdir(root_dir)  # 列出文件夹下所有的目录与文件
           for dir in dirlist:
               path = os.path.join(root_dir, dir)
               if os.path.isfile(path):
                   while self.recycle:
                       time.sleep(0.05)
                   if self.finderCallback:
                       self.finderCallback.onFindFile(path, os.path.getsize(path))
                       self.finderCallback.onRefresh()
                       if not self.off:
                           self.recycle = True
               else:
                   while self.recycle:
                       time.sleep(0.05)
                   if self.finderCallback:
                       self.finderCallback.onFindDir(path)
                       self.finderCallback.onRefresh()
                       if not self.off:
                           self.recycle = True
                   # 递归调用(当遍历到文件夹时,继续遍历,直到当前文件夹下没有文件夹为止)
                   self.list_flie(path)

By inheriting FinderCallback and overriding onFindDir and onFindFile, the program sends appropriate control commands to the receiver during traversal.

Running the programs :

Start the receiver (server) on a host that has an accessible IP (preferably within a LAN):

python3 ftserver.py -i 10.135.xxx.xxx -d /home/ubuntu/downloads

Run the sender (client) on another machine, specifying the server’s public IP and the folder to transfer:

python3 ftclient.py -i 111.120.xxx.xxx -f /Users/capton/desktop/bilibili

Because many Chinese cloud providers use NAT, the public and private IPs must be correctly configured for the two endpoints to communicate.

Note: The system works best on a local network where IPs are directly reachable; using public networks requires knowledge of both the remote host’s public and internal IP addresses.

- END -

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Network programmingSocketfile transfer
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.