亚洲欧美日韩综合系列在线_91精品人妻一区二区_欧美大肥婆一级特大AA片_九色91视频免费观看_亚洲综合国产精品_av中文字幕在线不卡_久久精品色综合网_看黄色视频的软件_无卡无码高清中文字幕码2024_亚洲欧美日韩天堂网

python自己動手從零開始搭建FTP服務器2 FTP初步框架

來源:豐年留客 發(fā)布時間:2018-11-03 16:18:22 閱讀量:1288

 開始添加FTP框架

    通過學習FTP協(xié)議,我們知道FTP維護了兩個TCP連接。一個是控制連接,一個是數(shù)據(jù)連接??刂七B接走的是控制信息、命令等。數(shù)據(jù)連接是用來發(fā)送文件和目錄的。  為什么要這么設計呢?剛好在學習TCP/IP協(xié)議棧,嘗試解釋下。FTP中的命令,都是簡單的幾個字符組成的,最多加上命令參數(shù)不過100個字節(jié)以內(nèi)。而文件往往是以MB來計的。所以在發(fā)送命令時,一個IP包往往是利用了一小部分,如我的wlan卡,MTU是1500字節(jié)。而文件被發(fā)送時,每個包都是裝滿數(shù)據(jù)的。兩者遵循的TCP處理方式也不同,小分組比較多時,會浪費掉大部分的帶寬,系統(tǒng)會執(zhí)行NAGLE算法,對小數(shù)據(jù)包進行合并發(fā)送,以提高網(wǎng)絡帶寬的利用率。大分組則會全力發(fā)送,只要窗口允許,帶寬允許。

    FTP具體的協(xié)議要求為,客戶端為控制連接的發(fā)起端,服務器則是數(shù)據(jù)連接的發(fā)起端。當客戶端想要傳輸某個文件時,通過控制連接向服務器端發(fā)起請求,并告知自己可用的臨時端口號,客戶端會去監(jiān)聽這個端口號。由服務器發(fā)起數(shù)據(jù)連接,把文件傳輸過來。注意,服務器端兩個TCP連接的端口號都是20,要求端口復用。我這里實現(xiàn)時,只保證服務器端兩個連接使用相同的端口號即可,是不是20,我不關心。也不重要。

    這次要實現(xiàn)的是在此前的基礎上添加以下特性。

    1)添加控制連接,和數(shù)據(jù)連接。

    2)實現(xiàn)通過控制連接傳輸請求,通過數(shù)據(jù)連接傳輸文件。

    FTP的基本命令不在此次實現(xiàn)的范圍內(nèi)。通過初步的嘗試發(fā)現(xiàn),客戶端的單線程已經(jīng)遇到了致命問題。一方面我們要接受用戶的輸入,來向服務器傳遞命令,同時又要監(jiān)聽一個本地窗口。如果先發(fā)送命令,則等到服務器發(fā)起連接時,客戶端的端口還沒有處于監(jiān)聽狀態(tài),導致連接無法進行。而另一方面,如果先監(jiān)聽,則此時socket處于阻塞狀態(tài),無法接收用戶的輸入。這就是一個矛盾狀態(tài)了。沒有辦法了,反復試驗,只能采用多線程來實現(xiàn)。

    具體做法是:

    1)當收到用戶要傳送文件的命令(g),就開啟一個線程,用來啟動一個臨時的數(shù)據(jù)連接,監(jiān)聽本地的一個端口。

    2)線程啟動后,則在主線程中,通過控制連接向服務器發(fā)送傳輸文件的命令。

    3)服務器接受到傳輸文件的命令后,向客戶端發(fā)發(fā)起數(shù)據(jù)連接。并把文件發(fā)送給客戶端。

    4)文件發(fā)送完成后,客戶端線程退出,數(shù)據(jù)連接關閉。

    目前的實現(xiàn)中。還沒有加入端口的傳遞信息。還是默認傳輸tmp文件。


  代碼如下,在手機和電腦之間進行了測試。可以接收,但是手機上運行客戶端,沒有寫權(quán)限。


#! /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)) #根據(jù)需要更改地址

    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()


--------------------- 

作者:豐年留客 

來源:CSDN 

原文:https://blog.csdn.net/u012520854/article/details/53575134 

版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!


標簽: 服務器搭建
分享:
評論:
你還沒有登錄,請先