當前位置:首頁 » 文件管理 » socket實現ftp

socket實現ftp

發布時間: 2023-12-10 15:35:33

『壹』 用ftp傳輸和socket傳輸 具體區別在哪裡

ftp是文件傳輸協議,只是定義了數據包傳輸相關控制細節和應用層封為包格式。其真正進行數據的傳輸時使用的還是socket介面。

『貳』 如何非同步讀取FTP

一:開發背景
由於需要對多個伺服器發布大的數據包,所以自己在LINUX用C語言,開發了一個傳送器工具。因為上傳時需要支持斷點續傳,所以自己參考ftp-rfc959和一些文章開發了這個支持斷點續傳的上傳工具。整個工具分兩部分開發的:一是支持斷點續傳的Ftp工具,包含下載和上傳功能。二是同時對多個伺服器發布不同數據包的傳送器工具。本文只是對斷點續傳的商船和下載作探討。

二:實現
其實Ftp上傳下載的實現很簡單,首先Ftp伺服器端要支持文件的定位,
然後就是通過建立的Socket用Ftp伺服器命令和伺服器交互.
有些也可以通過Socket做自己的客戶端和伺服器端,但是有些伺服器是自己能管理控制的,而且原來自己也寫過一些這樣C/S模式的工具,簡單消息的傳送接收還不錯。
但用來傳輸文件效率很低,比文件傳送協議FTP(File Transfer Protocol)差的太多。 利用Ftp的服務端可以省去伺服器端的開發,而且可以向任何開放Ftp服務的伺服器上傳送文件,可以不考慮對方安裝的
是什麼的操作系統。

三:FTP
文件傳送協議 FTP 只提供文件傳送的一些基本的服務,它使用 TCP 可靠的運輸服務。FTP 的主要功能是減少或消除在不同操作系統下處理文件的不兼容性。
FTP 使用客戶伺服器方式。
一個 FTP 伺服器進程可同時為多個客戶進程提供服務。FTP的伺服器進程由兩大部分組成:一個主進程,負責接受新的請求;另外有若干個從屬進程,負責處理單個請求。
A、通常的方式:
控制連接在整個會話期間一直保持打開,FTP 客戶所發出的傳送請求通過控制連接發送給控制進程,但控制連接並不用來傳送文件,實際用於傳輸文件的是「數據連接」。
控制進程在接收到 FTP 客戶發送來的文件傳輸請求後就創建一個「數據傳送進程」和一個「數據連接」,並將數據連接連接到「數據傳送進程」,數據傳送進程實際完成文件的傳送,在傳送完畢後關閉「數據傳送連接」並結束運行
當客戶進程向伺服器進程發出建立連接請求時,要尋找連接伺服器進程的熟知埠(21),同時還要告訴伺服器進程自己的另一個埠號碼,用於建立數據傳送連接。接著,伺服器進程用自己傳送數據的熟知埠(20)與客戶進程所提供的埠號碼建立數據傳送連接。

B、 被動模式:
FTP客戶端發出的連接請求,一般通過伺服器的21號埠建立控制連接,專門用來傳輸一些字元串命令和響應信息。控制命令通道一定是由客戶端向伺服器的連接(默認的埠是21,也可以指定埠,這要看伺服器的設置)。
PASV:通過控制通道通過發送PASV 伺服器命令到 FTP伺服器。請求建立被動模式數據連接通道。 (客戶端的命令 passive)
伺服器返回連接的信息(227 Entering Passive Mode (70,0,10,62,120,18) )地址和埠。埠=最後第二位乘256再加上最後一位(120*256+18)。(注意埠設為0的情況) 如: *f_port = atoi(port_1) * 256 + atoi(port_2);
伺服器端和客戶端身份轉換,原客戶端在本地建立監聽,監聽來自原伺服器遠端的連接請求建立數據連接通道。
四、 實現方法:
A、下載:
1、向伺服器發送「REST + 本地文件長度」,告訴伺服器,客戶端要斷點下載了。這時伺服器還不知道客戶端要下載的文件名;
2、向伺服器發送"RETR + 文件名",通知伺服器要下載的文件名,這時伺服器開始定位文件指針讀文件並發送數據。
3、客戶端定位本地文件指針偏移到文件末尾;
4、兩端的准備工作都做完了以後,客戶端創建socket,以被動或非被動方式建立數據鏈接,循環調用recv接收文件數據並追加到本地文件末尾;

B、上傳:
1、獲取伺服器上和本地要上傳文件的同名文件大小;
2、向伺服器發送「APPE + 文件名」,通知伺服器,從數據通道發送給你的數據要附加到這個文件末尾。
3、定位本地文件指針,文件指針偏移到指定位置,這個位置與FTP伺服器上文件大小相同的位置。
4、從文件指針處讀數據並發送。

C、Ftp伺服器命令
我們平時使用的命令,大多是客戶端的。伺服器端的命令可以參考下面:
命令 描述
ABOR 中斷數據連接程序 ACCT <account> 系統特權帳號
ALLO <bytes> 為伺服器上的文件存儲器分配位元組 APPE <filename> 添加文件到伺服器同名文件
CDUP <dir path> 改變伺服器上的父目錄 CWD <dir path> 改變伺服器上的工作目錄
DELE <filename> 刪除伺服器上的指定文件 HELP <command> 返回指定命令信息 LIST <name> 如果是文件名列出文件信息,如果是目錄則列出文件列表 MODE <mode> 傳輸模式(S=流模式,B=塊模式,C=壓縮模式)
MKD <directory> 在伺服器上建立指定目錄 NLST <directory> 列出指定目錄內容
NOOP 無動作,除了來自伺服器上的承認 PASS <password> 系統登錄密碼
PASV 請求伺服器等待數據連接 PORT <address> IP 地址和兩位元組的埠 ID PWD 顯示當前工作目錄 QUIT 從 FTP 伺服器上退出登錄
REIN 重新初始化登錄狀態連接 REST <offset> 由特定偏移量重啟文件傳遞
RETR <filename> 從伺服器上找回(復制)文件 RMD <directory> 在伺服器上刪除指定目錄
RNFR <old path> 對舊路徑重命名 RNTO <new path> 對新路徑重命名
SITE <params> 由伺服器提供的站點特殊參數 SMNT <pathname> 掛載指定文件結構
STAT <directory> 在當前程序或目錄上返回信息 STOR <filename> 儲存(復制)文件到伺服器上
STOU <filename> 儲存文件到伺服器名稱上 STRU <type> 數據結構(F=文件,R=記錄,P=頁面)
SYST 返回伺服器使用的操作系統 TYPE <data type> 數據類型(A=ASCII,E=EBCDIC,I=binary)
USER <username>> 系統登錄的用戶名
D、伺服器返回的部分數字代碼含義
125 Data connection already open; Transfer starting.
226 Transfer complete.
227 Entering Passive Mode (127,0,0,1,4,18).
230 User xxxxx logged in.
331 Password required for xxxxx.
425 Can』t open data connection.
226 Closing data connection.
200 return a state of TYPE or MODE commond
220 connection state
五、關於Socket
關於Socket編程有很多參考資料,這里不作詳細說明
Socket是應用層與TCP/IP協議族通信的中間軟體抽象層,它是一組介面
Socket 是一個基本的通信機制Socket把復雜的TCP/IP協議族隱藏在Socket介面後面,對用戶來說,一組簡單的介面就是全部,讓Socket去組織數據,以符合指定的協議.
Socket也具有一個類似於打開文件的函數調用Socket(),該函數返回一個整型的Socket描述符,隨後的連接建立、數據傳輸等操作都是通過該Socket實現的。
常用的Socket類型有兩種:
A、流式Socket(SOCK_STREAM):流式是一種面向連接的Socket,針對於面向連接的TCP服務應用。
B、數據報式Socket(SOCK_DGRAM):數據報式Socket是一種無連接的Socket,對應於無連接的UDP服務應用。
Socket的程序是一種C/S結構,分客戶端和伺服器端。
A、客戶端
– 初始化Socket
– 連接伺服器(connect),如果連接成功,這時客戶端與伺服器端的連接就建立了
– 客戶端發送數據請求,伺服器端接收請求並處理請求,然後把回應數據發送給客戶端
– 客戶端讀取數據,最後關閉連接,一次交互結束。
B、伺服器端
- 初始化Socket
- 埠綁定(bind)
- 監聽(listen)埠
- 調用accept阻塞,等待客戶端連接
在這里我們使用的就是面向連接的流式Socket,只編寫客戶端的程序。

六、代碼:
下面僅提供一個編譯過並在使用中的函數簡單的說明其實現原理,
需要有一點C語言和Linux/UNIX的socket編程基礎即可理解。
只是建立連接和傳輸部分的一個函數。當文件傳出結束或斷開時,
可以調用檢查函數看是否成功,位元組是否正常等,如果不正常結束,
可以再次循環調用它並定為伺服器文件的位元組,繼續傳輸。
其他的控制和功能都在其他函數中實現。為移植方便使用標准C語法符合C89標准。
code:
/*****************************************************************
* FileName: uftt_ver5.c *
* Company: algorithmics china lib Co.,Ltd. *
* Author: G.L.Zhang --- zglcl008 *
* Time: [2006-12-20] *
* Description: uninterrupted file transfers tools *
*****************************************************************/

int f_file_trans(const char *ft_addr, int ft_port, const char *ft_usr,const char *ft_pwd, const char *ft_opt, const char *ft_src, char *ft_obj, int ft_flg)
{
int cmd_sock = -1;
int dat_sock = -1;
int stream_sock= -1;
int dat_port = 0;
char dat_buffer[1024*5];
struct sockaddr_in f_server;
struct sockaddr_in f_datasvr;
unsigned char *pasv_ip = NULL;
unsigned char *pasv_port = NULL;
unsigned int len_addr = 0;
long rc_size = 0;
/* long svr_file_size = 0; */
long file_size = 0;
int rc = 0;
if (ft_addr == NULL || ft_usr == NULLft_pwd == NULL ||
ft_opt == NULL || ft_src == NULL || ft_obj == NULL ||
ft_port == 0 || ft_flg < 0) {
err_quit("--- file transfers parameter error");
}
/* get ftp commomd socket */
if ((cmd_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("cmmond socket");
err_quit("--- command sock error");
}

bzero(&f_server, sizeof(f_server));
f_server.sin_family = AF_INET;
f_server.sin_port = htons(ft_port);
f_server.sin_addr.s_addr = inet_addr(ft_addr);

if (connect(cmd_sock, (struct sockaddr *)&f_server, sizeof(f_server)) < 0) {
perror("connect");
err_quit("--- command sock error");
}
rc = uftt_cmd(dat_buffer, cmd_sock, NULL);
if (rc == 220)
printf("-1- %d OK\n", rc);
else
printf("-1- %d ERR\n", rc);

rc = uftt_cmd(dat_buffer, cmd_sock,"USER %s",ft_usr);
if (rc == 331)
printf("-2- %d OK\n", rc);
else
printf("-3- %d ERR\n", rc);
rc = uftt_cmd(dat_buffer, cmd_sock,"PASS %s",ft_pwd);
if (rc == 230)
printf("-3- %d OK\n", rc);
else
printf("-3- %d ERR\n", rc);
rc = uftt_cmd(dat_buffer, cmd_sock, "TYPE I");
if (rc == 200)
printf("-41- %d OK\n", rc);
else
printf("-41- %d ERR\n", rc);
rc = uftt_cmd(dat_buffer, cmd_sock, "MODE S");
if (rc == 200)
printf("-42- %d OK\n", rc);
else
printf("-42- %d ERR\n", rc);

memset(dat_buffer, ''\0'', sizeof(dat_buffer));
rc = uftt_cmd(dat_buffer, cmd_sock, "PASV");
if (rc == 227)
printf("-5- %d OK\n", rc);
else
printf("-5- %d ERR\n", rc);
#ifdef ZGL_DEBUG
printf("-5- %d %s\n", rc, dat_buffer);
#endif
/* get passive port */
dat_port = 0;
if ((rc = get_svr_port(dat_buffer, (int *)&dat_port)) < 0)
err_quit("data stream port error");
#ifdef ZGL_DEBUG
printf("--- pasive port=[%d]\n", dat_port);
#endif
if ((dat_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("data socket");
err_quit("--- data sock error");
}
len_addr = sizeof(f_datasvr);
bzero(&f_datasvr, sizeof(f_datasvr));
rc = getsockname(cmd_sock, (struct sockaddr *)&f_datasvr, (unsigned int *)&len_addr);
f_datasvr.sin_port = htons(dat_port);
/* 0=all port or appoint port TEST OK ***
f_datasvr.sin_port = htons(dat_port);
f_datasvr.sin_port = 0;
*/
if (bind(dat_sock,(struct sockaddr *)&f_datasvr,len_addr) == -1)
err_sys("--- data sock bind error");
if (listen(dat_sock,1) == -1)
err_sys("--- data sock bind error");
rc = getsockname(dat_sock, (struct sockaddr *)&f_datasvr, (unsigned int *)&len_addr);
pasv_ip = (unsigned char *)&f_datasvr.sin_addr;
pasv_port = (unsigned char *)&f_datasvr.sin_port;
rc = uftt_cmd(dat_buffer, cmd_sock,"PORT %d,%d,%d,%d,%d,%d",pasv_ip[0],
pasv_ip[1], pasv_ip[2], pasv_ip[3], pasv_port[0], pasv_port[1]);
if (rc == 200)
printf("-6- %d OK\n", rc);
else
printf("-6- %d ERR\n", rc);

/* get RETR put STOR append APPE */
if (ft_flg == 0) {
rc = uftt_cmd(dat_buffer, cmd_sock, "STOR %s", ft_obj);
}
else if (ft_flg > 0){
rc = uftt_cmd(dat_buffer, cmd_sock, "APPE %s", ft_obj);
}
if (rc == 150)
printf("-7- %d OK\n", rc);
else
printf("-7- %d ERR\n", rc);
stream_sock = accept(dat_sock, (struct sockaddr *)&f_datasvr, (unsigned int *)&len_addr);
if (stream_sock < 0)
err_sys("--- stream socket error");
rc_size = f_put_file(stream_sock, ft_src, ft_obj, ft_flg, file_size);
/* do without ***
rc = uftt_cmd(dat_buffer, dat_sock,"QUIT");
printf("-8- %d \n", rc);
*/
close(stream_sock);
close(dat_sock);
rc = uftt_cmd(dat_buffer, cmd_sock,"QUIT");
if (rc == 226)
printf("-9- %d OK\n", rc);
else
printf("-9- %d ERR\n", rc);
close(cmd_sock);
return rc_size ;
}

『叄』 關於文件傳輸:socket直連,http,ftp,哪種方式更好

p2p 是更快的——UDP多線程傳輸,但相對尺皮要復陵襲差雜很多。

socket 自定義協議,應該僅次

然後 FTP
最好HTTP——但HTTP也可以使用PUT、多禪咐線程

熱點內容
做解壓橡皮 發布:2025-01-21 15:03:06 瀏覽:990
雙系統win訪問mac 發布:2025-01-21 14:53:52 瀏覽:484
安卓車機系統如何安裝carplay 發布:2025-01-21 14:52:24 瀏覽:589
sql操作手冊 發布:2025-01-21 14:46:08 瀏覽:311
青橙腳本 發布:2025-01-21 14:44:05 瀏覽:218
東風本田crv時尚版是什麼配置 發布:2025-01-21 14:20:04 瀏覽:219
安卓如何多開軟體每個機型不一樣 發布:2025-01-21 14:15:29 瀏覽:501
iis配置php5 發布:2025-01-21 14:08:19 瀏覽:274
凱叔講故事為什麼聯系不到伺服器 發布:2025-01-21 13:56:50 瀏覽:387
linux鏡像文件下載 發布:2025-01-21 13:34:36 瀏覽:218