python socket实现简单文件的传输

python 专栏收录该内容
3 篇文章 0 订阅

python源代码链接:https://github.com/AbnerKou/Burgess

     要实现简单文件的传输我们必须考虑这些问题:                

   1.客户端与服务端如何通信?

    其实说白了就是互联网中两个主机该如何通信,首先我们用ip地址可以标示一台主机,这样就可以通信了么?当然也不行,我们还得标示主机中的进程,当然协议也是不可或缺的,是udp报文协议还是tcp数据流协议,这的看你个人的需求。用套接字来作为一个标示符,唯一标识网络进程。

    想明白这两个问题我觉得这个问题有三分之一已经解决了,接下来呢我选择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的接收意味着应用进程在相应的连接上再也接收不到额外数据;一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;接收到这个FIN的源发送端TCP对它进行确认。

服务端代码:

<strong>#!/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</strong>


客户端代码:

 

 

<strong>#!/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()</strong>

运行截图:

服务端:

客户端:

  

 

 

 

 
  • 6
    点赞
  • 6
    评论
  • 5
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值