当前位置: 移动技术网 > IT编程>脚本编程>Python > python自己动手从零开始搭建FTP服务器2 FTP初步框架

python自己动手从零开始搭建FTP服务器2 FTP初步框架

2018年04月14日  | 移动技术网IT编程  | 我要评论

收官之作是什么意思,库伦旗政府网,移动手机刷钻代码

5 开始添加FTP框架

通过学习FTP协议,我们知道FTP维护了两个TCP连接。一个是控制连接,一个是数据连接。控制连接走的是控制信息、命令等。数据连接是用来发送文件和目录的。 为什么要这么设计呢?刚好在学习TCP/IP协议栈,尝试解释下。FTP中的命令,都是简单的几个字符组成的,最多加上命令参数不过100个字节以内。而文件往往是以MB来计的。所以在发送命令时,一个IP包往往是利用了一小部分,如我的wlan卡,MTU是1500字节。而文件被发送时,每个包都是装满数据的。两者遵循的TCP处理方式也不同,小分组比较多时,会浪费掉大部分的带宽,系统会执行NAGLE算法,对小数据包进行合并发送,以提高网络带宽的利用率。大分组则会全力发送,只要窗口允许,带宽允许。

FTP具体的协议要求为,客户端为控制连接的发起端,服务器则是数据连接的发起端。当客户端想要传输某个文件时,通过控制连接向服务器端发起请求,并告知自己可用的临时端口号,客户端会去监听这个端口号。由服务器发起数据连接,把文件传输过来。注意,服务器端两个TCP连接的端口号都是20,要求端口复用。我这里实现时,只保证服务器端两个连接使用相同的端口号即可,是不是20,我不关心。也不重要。

这次要实现的是在此前的基础上添加以下特性。

1)添加控制连接,和数据连接。

2)实现通过控制连接传输请求,通过数据连接传输文件。

FTP的基本命令不在此次实现的范围内。通过初步的尝试发现,客户端的单线程已经遇到了致命问题。一方面我们要接受用户的输入,来向服务器传递命令,同时又要监听一个本地窗口。如果先发送命令,则等到服务器发起连接时,客户端的端口还没有处于监听状态,导致连接无法进行。而另一方面,如果先监听,则此时socket处于阻塞状态,无法接收用户的输入。这就是一个矛盾状态了。没有办法了,反复试验,只能采用多线程来实现。

具体做法是:

1)当收到用户要传送文件的命令(g),就开启一个线程,用来启动一个临时的数据连接,监听本地的一个端口。

2)线程启动后,则在主线程中,通过控制连接向服务器发送传输文件的命令。

3)服务器接受到传输文件的命令后,向客户端发发起数据连接。并把文件发送给客户端。

4)文件发送完成后,客户端线程退出,数据连接关闭。

目前的实现中。还没有加入端口的传递信息。还是默认传输tmp文件。

代码如下,在手机和电脑之间进行了测试。可以接收,但是手机上运行客户端,没有写权限。

 

#! /usr/bin/python
# -*- coding: utf-8 -*-
# client side

import socket
from threading import *
import time


def get_file():
    data_socket_s = socket.socket()
    data_socket_s.bind(('0.0.0.0', 8001))
    data_socket_s.listen(1)
    data_socket_c, data_socket_c_addr = data_socket_s.accept() 
    if data_socket_c:
        print 'get a server connection'
        file_data = data_socket_c.recv(1024)
        f = open('tmp', 'w')
        f.write(file_data)
        f.close()
    data_socket_c.close()
    data_socket_s.close()

if __name__ == '__main__':
    control_socket = socket.socket()
    control_socket.connect(('127.0.0.1', 8000)) #根据需要更改地址
    print 'connected'
    while True:
        print 'sending data'
        in_data = raw_input('>>')
        if in_data == 'q':
            break;
        if in_data == 'g': #开启接受文件线程
            file_thread = Thread(target = get_file)
            file_thread.start()
            time.sleep(0.5)
            control_socket.send('g')
            file_thread.join()
        else:
            control_socket.send(in_data)

    print 'end'
    control_socket.close()

#! /usr/bin/python
# -*- coding: utf-8 -*-
# server side

from socket import *

if __name__ == '__main__':
    s_listen_socket = socket()
    s_listen_socket.bind(('0.0.0.0', 8000))
    print 'b4 listening'
    s_listen_socket.listen(2)
    
    control_socket, client_addr  = s_listen_socket.accept()
#    control_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    print client_addr[0]
    print 'incoming connection'
    if control_socket: 
        while True:
            recv_data = control_socket.recv(20)
            if not recv_data:
                break;
            print 'control receiving %s' % recv_data
            if recv_data == 'g':
                print 'sending file tmp'
                data_socket = socket()
#                data_socket.bind(('127.0.0.2', 8001))
                data_socket.connect((client_addr[0], 8001))
                out_file = open('tmp', 'r')
                send_data = out_file.read()
                data_socket.send(send_data)
                out_file.close()
                data_socket.close()
                recv_data = ''
                print 'sending file tmp done'
            else:
                print 'receiving %s' % recv_data
                control_socket.send(recv_data)
    print 'end'
    s_listen_socket.close()
    control_socket.close()


 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网