Python基于Socket实现C/S架构文件传输详解

Mason
Mason
发布时间:2026-10-13 | 5人浏览过
原创

本文详细解析了基于Python Socket库构建C/S架构的文件传输系统。通过TCP协议实现客户端与服务端的双向通信,涵盖socket创建、绑定监听、三次握手及四次挥手等核心网络概念。服务端监听9500端口,支持ls查看、put上传及get下载指令,配合二进制读写实现稳定文件传输,适合初学者理解网络编程基础。

本文分享使用Python实现C/S架构进行简单文件传输的代码示例,供读者参考。

实现简单的文件传输功能,需要首先明确以下核心问题:

1. 什么是C/S架构?

C/S架构即客户端/服务器(Client/Server)架构。尽管不同人对它的理解可能有所差异,但其核心定义一致:服务器是一种软件或硬件实体,旨在向一个或多个客户端提供服务。服务器的主要职责是等待客户端请求,处理这些请求,随后继续等待其他请求。

2. 客户端与服务器如何建立通信?

本质上,这是互联网中两个主机之间的通信过程。首先,通过IP地址标识一台主机,但这不足以完成通信,还需要标识主机内的具体进程。此外,通信协议不可或缺,需根据需求选择UDP报文协议或TCP数据流协议。套接字(Socket)作为标识符,用于唯一标识网络进程。

厘清上述两个问题后,该任务的基础已解决三分之一。接下来,本例选择TCP协议进行数据传输。

服务端实现逻辑:

使用socket()函数定义Socket描述字。

调用bind()函数将地址族中的特定地址分配给Socket,即将IPv4或IPv6地址与端口号的组合绑定到Socket上。

使用listen()函数将Socket设置为被动模式,以等待客户端的连接请求。

当客户端发送消息时,服务端通过accept()函数接收请求,并返回客户端的Socket描述字。随后,服务端利用该描述字与客户端进行信息的发送和接收。

本程序旨在实现文件传输,设计思路类似于FTP程序,满足客户上传和下载文件的需求。服务端启动后监听端口(此处使用9500),等待客户端连接。客户端通过三次握手建立连接后,可输入命令向服务端发起请求:输入“ls”命令可查看服务端可供下载的文件列表;输入“put 文件名”可上传文件,输入“get 文件名”可下载文件。在上传文件时,客户端以二进制方式打开本地文件读取内容,并调用send()函数发送文件数据;服务端则以写入方式打开目标文件,将客户端上传的数据写入其中,从而完成文件上传。下载过程与此类似:客户端发送“get 文件名”命令,并以写入方式打开本地文件;服务端收到命令后以读取方式打开源文件,并将内容发送给客户端。

TCP三次握手建立连接过程:

当客户端调用connect()时,触发连接请求,向服务器发送SYN J包,此时connect()进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept()函数接收请求并向客户端发送SYN K和ACK J+1,此时accept()进入阻塞状态;客户端收到服务器的SYN K和ACK J+1后,connect()返回,并对SYN K进行确认;服务器收到ACK K+1时,accept()返回,至此三次握手完毕,连接建立。

TCP四次挥手断开连接过程:

某个应用进程首先调用close()主动关闭连接,此时TCP发送一个FIN M;另一端接收到FIN M后,执行被动关闭,并对该FIN进行确认。FIN的接收作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;一段时间之后,接收到文件结束符的应用进程调用close()关闭它的Socket。这导致其TCP也发送一个FIN N;接收到这个FIN的源发送端TCP对其进行确认。

服务端完整代码:

#!/usr/bin/env python
from socket import *
import time
import sys
import os
 
HOST = 'localhost'
PORT = 9500
BUFIZ = 1024
ADDR = (HOST,PORT)
 
def recvfile(filename):
 print 'starting receive file...'
 f = open(filename,'wb')
 cliSockfd.send('no problem')
 while True:
  data = cliSockfd.recv(4096)
  if data == 'EOF':
   print 'recved file success!'
   break
  f.write(data)
 f.close()
 
def sendfile(filename):
 print 'starting send file...'
 cliSockfd.send('no problem')
 f = open(filename,'rb')
 while True:
  data = f.read(4096)
  if not data:
   break
  cliSockfd.send(data)
 f.close()
 time.sleep(1)
 cliSockfd.send('EOF')
 print 'send file success!'
def handle1(act,filename):
 if act == 'put':
  print 'recving msg!'
  recvfile(filename)
 elif act == 'get':
  print 'sending msg!'
  sendfile(filename)
 else:
  print 'error!'
 
def handle2(act):
 if act == 'ls':
  path = sys.path[0]
  every_file = os.listdir(path)
  for filename in every_file: 
   cliSockfd.send(filename + ' ')
  time.sleep(1)
  cliSockfd.send('EOF')
  print 'all filename has send to client success!'
 else:
  print 'command error'
 
sockfd = socket(AF_INET,SOCK_STREAM)
sockfd.bind(ADDR)
sockfd.listen(5)
while True:
 print 'waiting for connection...'
 cliSockfd,addr = sockfd.accept()
 print '...connected from:',addr
 
 while True:
  msg = cliSockfd.recv(4096)
  if msg == 'close':
   print 'client closed'
   break
  info = msg.split()
  if len(info) == 2:
   handle1(*info)
  elif len(info) == 1:
   handle2(*info)
  else:
   print 'command error!'
   break

客户端完整代码:

#!/usr/bin/env python
import sys
import socket
import time
HOST = 'localhost'
PORT = 9500
BUFSIZ = 1024
ADDR = (HOST,PORT)
 
cliSockfd = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 
def recvfile(filename):
 f = open(filename,'wb')
 while True:
  msg = cliSockfd.recv(4096)
  if msg == 'EOF':
   print 'recv file success!'
   break
  f.write(msg)
 f.close
def sendfile(filename):
 f = open(filename,'rb')
 while True:
  msg = f.read(4096)
  if not msg:
    break
  cliSockfd.sendall(msg)
 f.close()
 time.sleep(1)
 cliSockfd.sendall('EOF')
 print 'send file success'
def confirm(cliSockfd,client_command):
 cliSockfd.send(client_command)
 msg = cliSockfd.recv(4096)
 if msg == 'no problem':
  return True
 
def handle1(act,filename):
 if act == 'put':
  if confirm(cliSockfd,client_command):
   sendfile(filename)
  else:
   print 'server error1!'
 elif act == 'get':
  if confirm(cliSockfd,client_command):
   recvfile(filename)
  else:
   print 'server error2!'
 else:
  print 'command error!'
def handle2(act):
 if act == 'ls':
  cliSockfd.send('ls')
  while True:
   msg = cliSockfd.recv(1024)
   if msg == 'EOF':
    break
   print msg
 else:
  print 'command error'
 
try:
 cliSockfd.connect(ADDR)
 print 'connect to ',ADDR
 while True:
  client_command = raw_input('>>>')
  if not client_command:
   continue
  msg = client_command.split()
  if len(msg) == 2:
   handle1(*msg)
  elif len(msg) == 1 and msg != ['close']:
   handle2(*msg)
  elif len(msg) == 1 and msg == ['close']:
   cliSockfd.send('close')
   break
  else:
   print 'command error'
except socket.error,e:
 print 'error:',e
finally:
 cliSockfd.close()

运行效果截图:

服务端运行界面:

客户端运行界面:

欢迎各位技术专家提出宝贵意见。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表