最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

FTP客戶端c代碼功能實現(xiàn)

2023-02-24 08:53 作者:程序員-王堅  | 我要投稿

現(xiàn)在市面上有很多免費的FTP軟件:如FileZilla ,那如果想自己在代碼中實現(xiàn)與ftp服務(wù)器的上傳下載文件該如何實現(xiàn)那??

本質(zhì)上ftp協(xié)議就是TCP基礎(chǔ)上建立的一種協(xié)議,具體如下。

FTP 概述

文件傳輸協(xié)議(FTP)作為網(wǎng)絡(luò)共享文件的傳輸協(xié)議,在網(wǎng)絡(luò)應(yīng)用軟件中具有廣泛的應(yīng)用。FTP的目標(biāo)是提高文件的共享性和可靠高效地傳送數(shù)據(jù)。

在傳輸文件時,F(xiàn)TP 客戶端程序先與服務(wù)器建立連接,然后向服務(wù)器發(fā)送命令。服務(wù)器收到命令后給予響應(yīng),并執(zhí)行命令。FTP 協(xié)議與操作系統(tǒng)無關(guān),任何操作系統(tǒng)上的程序只要符合 FTP 協(xié)議,就可以相互傳輸數(shù)據(jù)。本文主要基于 LINUX 平臺,對 FTP 客戶端的實現(xiàn)原理進行詳盡的解釋并闡述如何使用 C 語言編寫一個簡單的 FTP 客戶端。

?

FTP 協(xié)議

相比其他協(xié)議,如 HTTP 協(xié)議,F(xiàn)TP 協(xié)議要復(fù)雜一些。與一般的 C/S 應(yīng)用不同點在于一般的C/S 應(yīng)用程序一般只會建立一個?Socket?連接,這個連接同時處理服務(wù)器端和客戶端的連接命令和數(shù)據(jù)傳輸。而FTP協(xié)議中將命令與數(shù)據(jù)分開傳送的方法提高了效率。

FTP 使用 2 個端口,一個數(shù)據(jù)端口和一個命令端口(也叫做控制端口)。這兩個端口一般是21 (命令端口)和 20 (數(shù)據(jù)端口)。控制 Socket 用來傳送命令,數(shù)據(jù) Socket 是用于傳送數(shù)據(jù)。每一個 FTP 命令發(fā)送之后,F(xiàn)TP 服務(wù)器都會返回一個字符串,其中包括一個響應(yīng)代碼和一些說明信息。其中的返回碼主要是用于判斷命令是否被成功執(zhí)行了。

命令端口

一般來說,客戶端有一個 Socket 用來連接 FTP 服務(wù)器的相關(guān)端口,它負(fù)責(zé) FTP 命令的發(fā)送和接收返回的響應(yīng)信息。一些操作如“登錄”、“改變目錄”、“刪除文件”,依靠這個連接發(fā)送命令就可完成。

數(shù)據(jù)端口

對于有數(shù)據(jù)傳輸?shù)牟僮?,主要是顯示目錄列表,上傳、下載文件,我們需要依靠另一個 Socket來完成。

如果使用被動模式,通常服務(wù)器端會返回一個端口號??蛻舳诵枰昧黹_一個 Socket 來連接這個端口,然后我們可根據(jù)操作來發(fā)送命令,數(shù)據(jù)會通過新開的一個端口傳輸。

如果使用主動模式,通??蛻舳藭l(fā)送一個端口號給服務(wù)器端,并在這個端口監(jiān)聽。服務(wù)器需要連接到客戶端開啟的這個數(shù)據(jù)端口,并進行數(shù)據(jù)的傳輸。

下面對 FTP 的主動模式和被動模式做一個簡單的介紹。

主動模式 (PORT)

主動模式下,客戶端隨機打開一個大于 1024 的端口向服務(wù)器的命令端口 P,即 21 端口,發(fā)起連接,同時開放N +1 端口監(jiān)聽,并向服務(wù)器發(fā)出 “port N+1” 命令,由服務(wù)器從它自己的數(shù)據(jù)端口 (20) 主動連接到客戶端指定的數(shù)據(jù)端口 (N+1)。

FTP 的客戶端只是告訴服務(wù)器自己的端口號,讓服務(wù)器來連接客戶端指定的端口。對于客戶端的防火墻來說,這是從外部到內(nèi)部的連接,可能會被阻塞。

被動模式 (PASV)

為了解決服務(wù)器發(fā)起到客戶的連接問題,有了另一種 FTP 連接方式,即被動方式。命令連接和數(shù)據(jù)連接都由客戶端發(fā)起,這樣就解決了從服務(wù)器到客戶端的數(shù)據(jù)端口的連接被防火墻過濾的問題。

被動模式下,當(dāng)開啟一個 FTP 連接時,客戶端打開兩個任意的本地端口 (N > 1024 和 N+1) 。

第一個端口連接服務(wù)器的 21 端口,提交 PASV 命令。然后,服務(wù)器會開啟一個任意的端口 (P > 1024 ),返回如“227 entering passive mode (127,0,0,1,4,18)”。 它返回了 227 開頭的信息,在括號中有以逗號隔開的六個數(shù)字,前四個指服務(wù)器的地址,最后兩個,將倒數(shù)第二個乘 256 再加上最后一個數(shù)字,這就是 FTP 服務(wù)器開放的用來進行數(shù)據(jù)傳輸?shù)亩丝?。如得?227 entering passive mode (h1,h2,h3,h4,p1,p2),那么端口號是 p1*256+p2,ip 地址為h1.h2.h3.h4。這意味著在服務(wù)器上有一個端口被開放??蛻舳耸盏矫钊〉枚丝谔栔? 會通過 N+1 號端口連接服務(wù)器的端口 P,然后在兩個端口之間進行數(shù)據(jù)傳輸。

主要用到的 FTP 命令

FTP 每個命令都有 3 到 4 個字母組成,命令后面跟參數(shù),用空格分開。每個命令都以 "\r\n"結(jié)束。

要下載或上傳一個文件,首先要登入 FTP 服務(wù)器,然后發(fā)送命令,最后退出。這個過程中,主要用到的命令有 USER、PASS、SIZE、REST、CWD、RETR、PASV、PORT、QUIT。

USER: 指定用戶名。通常是控制連接后第一個發(fā)出的命令?!癠SER gaoleyi\r\n”: 用戶名為gaoleyi 登錄。

PASS: 指定用戶密碼。該命令緊跟 USER 命令后。“PASS gaoleyi\r\n”:密碼為 gaoleyi。

SIZE: 從服務(wù)器上返回指定文件的大小。“SIZE file.txt\r\n”:如果 file.txt 文件存在,則返回該文件的大小。

CWD: 改變工作目錄。如:“CWD dirname\r\n”。

PASV: 讓服務(wù)器在數(shù)據(jù)端口監(jiān)聽,進入被動模式。如:“PASV\r\n”。

PORT: 告訴 FTP 服務(wù)器客戶端監(jiān)聽的端口號,讓 FTP 服務(wù)器采用主動模式連接客戶端。如:“PORT h1,h2,h3,h4,p1,p2”。

RETR: 下載文件?!癛ETR file.txt \r\n”:下載文件 file.txt。

STOR: 上傳文件。“STOR file.txt\r\n”:上傳文件 file.txt。

REST: 該命令并不傳送文件,而是略過指定點后的數(shù)據(jù)。此命令后應(yīng)該跟其它要求文件傳輸?shù)?FTP 命令?!癛EST 100\r\n”:重新指定文件傳送的偏移量為 100 字節(jié)。

QUIT: 關(guān)閉與服務(wù)器的連接。

FTP 響應(yīng)碼

客戶端發(fā)送 FTP 命令后,服務(wù)器返回響應(yīng)碼。

響應(yīng)碼用三位數(shù)字編碼表示:

第一個數(shù)字給出了命令狀態(tài)的一般性指示,比如響應(yīng)成功、失敗或不完整。

第二個數(shù)字是響應(yīng)類型的分類,如 2 代表跟連接有關(guān)的響應(yīng),3 代表用戶認(rèn)證。

第三個數(shù)字提供了更加詳細(xì)的信息。

第一個數(shù)字的含義如下:

1 表示服務(wù)器正確接收信息,還未處理。

2 表示服務(wù)器已經(jīng)正確處理信息。

3 表示服務(wù)器正確接收信息,正在處理。

4 表示信息暫時錯誤。

5 表示信息永久錯誤。

第二個數(shù)字的含義如下:

0 表示語法。

1 表示系統(tǒng)狀態(tài)和信息。

2 表示連接狀態(tài)。

3 表示與用戶認(rèn)證有關(guān)的信息。

4 表示未定義。

5 表示與文件系統(tǒng)有關(guān)的信息。

Socket 編程的幾個重要步驟

Socket 客戶端編程主要步驟如下:

  1. socket() 創(chuàng)建一個 Socket

  2. connect() 與服務(wù)器連接

  3. write() 和 read() 進行會話

  4. close() 關(guān)閉 Socket

Socket 服務(wù)器端編程主要步驟如下:

  1. socket() 創(chuàng)建一個 Socket

  2. bind()

  3. listen() 監(jiān)聽

  4. accept() 接收連接的請求

  5. write() 和 read() 進行會話

  6. close() 關(guān)閉 Socket

實現(xiàn) FTP 客戶端上傳下載功能

下面讓我們通過一個例子來對 FTP 客戶端有一個深入的了解。本文實現(xiàn)的 FTP 客戶端有下列功能:

  1. 客戶端和 FTP 服務(wù)器建立 Socket 連接。

  2. 向服務(wù)器發(fā)送 USER、PASS 命令登錄 FTP 服務(wù)器。

  3. 使用 PASV 命令得到服務(wù)器監(jiān)聽的端口號,建立數(shù)據(jù)連接。

  4. 使用 RETR/STOR 命令下載/上傳文件。

  5. 在下載完畢后斷開數(shù)據(jù)連接并發(fā)送 QUIT 命令退出。

?

?

經(jīng)過測試可以正常上傳下載數(shù)據(jù),,測試代碼如下:

main.c
#include <stdio.h>#include <stdlib.h>#include <string.h>#include "ftp.h"#define FTP_SERVER_IP "XXXXXXXX"#define FTP_SERVER_USER "XXXXX"#define FTP_SERVER_PASS "XXXXXX"#define MAX_BUF_LEN 512typedef struct{ ? ?char usr[32]; ? ?char passwd[32]; ? ?char ser_filepath[512]; ? ?char ser_filename[64]; ? ?char new_filename[64]; ? ?int control_sock; }ftp_client_st; ftp_client_st ftp_st;int main (int argc , char * argv[]) { ? ?char str[MAX_BUF_LEN] ={0}; ? ?int ret =-1; ? ?// ? ? ? ?while(1){ ? ? ? ?printf("*************\n"); ? ? ? ?//printf("Please input the ftp server ip: "); ? ? ? ?memset(str,0,sizeof(str)); ? ? ? ?//scanf("%s",str); //從終端獲取到服務(wù)器ip地址。 ? ? ? ?strcpy(str,FTP_SERVER_IP); ? ? ? ?printf("input fpt server ip:%s\n",str); ? ? ? ?/*連接到服務(wù)器*/ ? ? ? ?memset(&ftp_st,0,sizeof(ftp_client_st)); ? ? ? ? ftp_st.control_sock = connect_ftp_server(str,FTP_SERVER_PORT); ? ? ? ?if(ftp_st.control_sock > 0){/*連接成功*/ ? ? ? ? ? ?ret = -1; ? ? ? ? ? ?while(ret < 0){ ? ? ? ? ? ? ? ? ? ?strcpy(ftp_st.usr,FTP_SERVER_USER); ? ? ? ? ? ? ? ?strcpy(ftp_st.passwd,FTP_SERVER_PASS); ? ? ? ? ? ? ? ?printf("input usr:%s passwd:%s\n",ftp_st.usr,ftp_st.passwd); ? ? ? ? ? ? ? ?ret = login_ftp_server(ftp_st.control_sock,ftp_st.usr,ftp_st.passwd); ? ? ? ? ? ? ? ?if(ret < 0){ ? ? ? ? ? ? ? ? ? ? ? ?printf("\nUser or Passwd is wrong,input agin"); ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ?else{ ? ? ? ? ? ? ? ? ? ?//打印服務(wù)器當(dāng)前目錄和列表 ? ? ? ? ? ? ? ? ? ?while(1){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?printf("Get list start:\n"); ? ? ? ? ? ? ? ? ? ? ? ?//ret = down_file_ftpserver(ftp_st.control_sock,"/","/list_mode",0,0,CMD_LIST); /*被動模式*/ ? ? ? ? ? ? ? ? ? ? ? ?ret = down_file_ftpserver(ftp_st.control_sock,"/","../list_passive",1,0,CMD_LIST); /*被動模式獲取文件列表*/ ? ? ? ? ? ? ? ? ? ? ? // down_file_ftpserver(ftp_st.control_sock,"/down_test","list1",0,0,CMD_LIST); ? ? ? ? ? ? ? ? ? ? ? ?//printf("\nInput down file dir (Input quit to quit):"); ? ? ? ? ? ? ? ? ? ? ? ?//memset(ftp_st.ser_filepath,0,sizeof(ftp_st.ser_filepath)); ? ? ? ? ? ? ? ? ? ? ? ?//scanf("%s",ftp_st.ser_filepath); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//if(strncmp(ftp_st.ser_filepath,"quit",4) ==0) ? ? ? ? ? ? ? ? ? ? ? ?// ? ?goto err0; ? ? ? ? ? ? ? ? ? ? #if 0 ? ? ? ? ? ? ? ? ? ? ? ? ?printf("\nInput ?down filename (Input quit to quit):"); ? ? ? ? ? ? ? ? ? ? ? ?memset(ftp_st.ser_filename,0,sizeof(ftp_st.ser_filename)); ? ? ? ? ? ? ? ? ? ? ? ?scanf("%s",ftp_st.ser_filename); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if(strncmp(ftp_st.ser_filename,"quit",4) ==0) ? ? ? ? ? ? ? ? ? ? ? ? ? ?goto err0; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?printf("\nInput new filename (Input quit to quit):"); ? ? ? ? ? ? ? ? ? ? ? ?memset(ftp_st.new_filename,0,sizeof(ftp_st.new_filename)); ? ? ? ? ? ? ? ? ? ? ? ?scanf("%s",ftp_st.new_filename); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if(strncmp(ftp_st.new_filename,"quit",4) ==0) ? ? ? ? ? ? ? ? ? ? ? ? ? ?goto err0; ? ? ? ? ? ? ? ? ? ? ? ? ? ?printf("input filename :%s; newfilename:%s; \n",ftp_st.ser_filename,ftp_st.new_filename); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?printf("down file start:\n"); ? ? ? ? ? ? ? ? ? ? ? ?//ret = down_file_ftpserver(ftp_st.control_sock,ftp_st.ser_filename,ftp_st.new_filename,0,0,CMD_RETR); ? ? ? ? ? ? ? ? ? ? ? ?ret = down_file_ftpserver(ftp_st.control_sock,ftp_st.ser_filename,ftp_st.new_filename,0,0,CMD_RETR); ? ? ? ? ? ? ? ? ? ? ? ?#endif ? ? ? ? ? ? ? ? ? ? ? ?down_file_ftpserver(ftp_st.control_sock,"/down_test/test_ftp.zip","../12.zip",1,0,CMD_RETR); ? ? ? ? ? ? ? ? ? ? ? ?up_file_ftpserver(ftp_st.control_sock, "/down_test/12.zip", "../12.zip", 1, 0); ? ? ? ? ? ? ? ? ? ? ? ?get_fsize_ftpserver(ftp_st.control_sock, "/down_test/12.zip"); ? ? ? ? ? ? ? ? ? ? ? ?goto err0; ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ?} ? ? ? ?} ? ? ? ? ? ?} err0: ? ? ? ?quit_fpt_server(ftp_st.control_sock); ? ?return 0; ? ? }

fpt.c

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <arpa/inet.h>#include <sys/unistd.h>#include <sys/ioctl.h>#include <net/if.h>#include "ftp.h"#define MAX_BUF 512#define IP_LENGTH ? 16//正常時服務(wù)器回復(fù)的響應(yīng)碼#define ACK_USER_NUM "331"#define ACK_PASS_NUM "230"#define ACK_PASV_NUM "227"#define ACK_CWD_NUM ?"250"#define ACK_SIZE_NUM "213"#define ACK_RETR_NUM "150" #define ACK_REST_NUM "350"#define ACK_QUIT_NUM "200"#define ACK_LIST_NUM "125"#define ACK_STOR_NUM "150"#define ACK_CONNECT_NUM "220"#define ACK_PORT_NUM "200"/*ftp server info*/typedef struct { ? ?//char szUserName[16]; ? ?//char szPassWd[32]; ? ?char server_path[128]; ? ?char server_filename[64]; ? ?char new_filename[128]; ? ?int data_sock; ? ?char data_ip[32]; ? ?int ?data_port; ? ?int client_server_sock; ? ?int file_handle; }FTP_DATA_INFO;static int itoa(int value, char * str, int radix);static int send_cmd(int ctrl_sock,eu_cmd_type typ, const char *val,const char *ack_num);static int enter_passive_mode(int ctrl_sock,char *data_ip, int * data_port);static int enter_active_mode(int ctrl_sock);static int get_data_sock(const char* server_ip,const int port);static int get_active_data_sock(int client_server_sock);static int GetAddr(const char *ifname, char *addr, int flag);static int close_st_info(FTP_DATA_INFO * info); FTP_DATA_INFO server_info;static int GetAddr(const char *ifname, char *addr, int flag) { ? ?struct sockaddr_in *sin; ? ?struct ifreq ifr; ? ?int sockfd; ? ?if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ? ?{ ? ? ? ?printf("socket create error!\n"); ? ? ? ?return - 1; ? ?} ? ?memset(&ifr, 0, sizeof(ifr)); ? ?strncpy(ifr.ifr_ifrn.ifrn_name, ifname, IFNAMSIZ); ? ?if(ioctl(sockfd, flag, &ifr) < 0) ? ?{ ? ? ? ?close(sockfd); ? ? ? ?return - 1; ? ?} ? ?close(sockfd); ? ?if(SIOCGIFHWADDR == flag) ? ?{ ? ? ? ?memcpy((void *)addr, (const void *)&ifr.ifr_ifru.ifru_hwaddr.sa_data, 6); ? ?} ? ?else ? ?{ ? ? ? ?sin = (struct sockaddr_in *)&ifr.ifr_ifru.ifru_addr; ? ? ? ?snprintf((char *)addr, IP_LENGTH, "%s", inet_ntoa(sin->sin_addr)); ? ?} ? ?return 0; }static int itoa(int value, char * str, int radix) { char temp[33]; ?char *tp = temp; ?int i; ?unsigned v; ?int sign; ?char *sp; ?int num= 0; ?if(radix > 36 || radix < 1) ? ?return 0; ?sign = (radix == 10 && value < 0); //十進制負(fù)數(shù) ?if(sign) ? ?v = -value; ?else ? ?v = (unsigned)value; ?while(v || tp == temp) ? ? ? //轉(zhuǎn)化操作 ?{ ? ?i = v % radix; ? ?v = v / radix; ? ?if(i < 10) ? ? ?*tp++ = i + '0'; ? ?else ? ? ?*tp++ = i + 'a' - 10; ?} ?if(str == 0) ? ?str = (char*)malloc((tp - temp) + sign + 1); ?sp = str; ?if(sign) ? //是負(fù)數(shù)的話把負(fù)號先加入數(shù)組 ? ?*sp++ = '-'; ?while(tp > temp) ?{ ? ?*sp++ = *--tp; ? ?num++; ?} ?*sp = 0; ? ?return num; }/** @brief 連接fpt服務(wù)器 * @param 無 * @return -1/成功建立的套接字*/int connect_ftp_server(const char* server_ip,const int port) { ? ?int control_sock =-1; ? ?int ret =-1; ? ?struct sockaddr_in server; ? ?char read_buf[MAX_BUF]={0}; ? ?struct timeval tv_out; ? ? ? ?memset(&server,0,sizeof(struct sockaddr_in)); ? ? ? ?if(server_ip == NULL){ ? ? ? ?printf("argc is NULL\n"); ? ? ? ?return -1; ? ?} ? ?control_sock = socket(AF_INET,SOCK_STREAM,0); ? ?if(control_sock <0){ ? ? ? ?printf("socket failed\n"); ? ? ? ?return -1; ? ?} ? ?/*設(shè)置sock fd 接收超時時間*/ ? ?tv_out.tv_sec =0; ? ?tv_out.tv_usec =500*1000; ? ?setsockopt(control_sock, SOL_SOCKET, SO_RCVTIMEO,&tv_out,sizeof(tv_out)); ? ? ? ? ? ?server.sin_family = AF_INET; ? ?server.sin_port = htons(port); ? ?server.sin_addr.s_addr = inet_addr(server_ip); ? ?ret = connect(control_sock,(struct sockaddr *)&server,sizeof(server)); ? ?if(ret < 0){ ? ? ? ?printf("connect failed\n"); ? ? ? ?return -1; ? ?} ? ?ret =1; ? ? ? ?/*接收服務(wù)端的應(yīng)答消息*/ ? ?usleep(100*1000); ? ?ret = read(control_sock,read_buf,sizeof(read_buf)); ? ?if(ret < 0){ ? ? ? ?printf("read error\n"); ? ? ? ?return -1; ? ?} ? ?printf("%s ret=%d \n",read_buf,ret); ? ?if(strncmp(read_buf,ACK_CONNECT_NUM,3) == 0) /*成功*/ ? ?{ ? ? ? ?printf("Connect ftp ok\n"); ? ? ? ?return control_sock; ? ?} ? ?else ? ?{ ? ? ? ?close(control_sock); ? ? ? ?return -1; ? ?} }/** @brief 被動模式連接獲取服務(wù)器的data_sock * @param 無 * @return -1/成功建立的套接字*/static int get_data_sock(const char* server_ip,const int port) { ? ?int data_sock =-1; ? ?int ret =-1; ? ?struct sockaddr_in server; ? ?char read_buf[MAX_BUF]={0}; ? ? ? ?memset(&server,0,sizeof(struct sockaddr_in)); ? ? ? ?if(server_ip == NULL){ ? ? ? ?printf("argc is NULL\n"); ? ? ? ?return -1; ? ?} ? ?data_sock = socket(AF_INET,SOCK_STREAM,0); ? ?if(data_sock <0){ ? ? ? ?printf("socket failed\n"); ? ? ? ?return -1; ? ?} ? ?/*設(shè)置為非阻塞*/ ? ?//int cflags = fcntl(data_sock,F_GETFL,0); ? ?//fcntl(data_sock,F_SETFL,cflags|O_NONBLOCK); ? ? ? ?server.sin_family = AF_INET; ? ?server.sin_port = htons(port); ? ?server.sin_addr.s_addr = inet_addr(server_ip); ? ?ret = connect(data_sock,(struct sockaddr *)&server,sizeof(server)); ? ?if(ret < 0){ ? ? ? ?printf("connect failed\n"); ? ? ? ?return -1; ? ?} ? ?/*無應(yīng)答*/ ? ?return data_sock; }/*主動模式獲取data sock ?必須要在LIST等下載上傳命令發(fā)送后 ?accept接受才能成功 ?*/static int get_active_data_sock(int client_server_sock) { ? ?int data_sock =-1; ? ?struct sockaddr_in client_name; ? ?int len; ? ?len = sizeof(client_name); ? ?data_sock = accept(client_server_sock,(struct sockaddr *)&client_name ,&len); ? ?if(data_sock <0) ? ?{ ? ? ? ?printf("accept failed\n"); ? ?} ? ?printf("data_sock = %d\n",data_sock); ? ? ? ?return data_sock; }/** @brief 登陸fpt服務(wù)器 * @param 無 * @return -1/成功返回0*/int login_ftp_server(int ctrl_sock,const char *user_name, const char * passwd) { ? ?int ret =-1; ? ?if((user_name == NULL) ||(passwd == NULL)){ ? ? ? ?printf("argc is NULL\n"); ? ? ? ?return -1; ? ?} ? ? ? ?ret = send_cmd(ctrl_sock,CMD_USER,user_name,ACK_USER_NUM); ? ?if(ret < 0){ ? ? ? ? ? ?printf("send_cmd ?%d failed \n",CMD_USER); ? ? ? ? ? ?return -1; ? ?} ? ?ret = send_cmd(ctrl_sock,CMD_PASS,passwd,ACK_PASS_NUM); ? ?if(ret < 0){ ? ? ? ? ? ?printf("send_cmd ?%d failed \n",CMD_PASS); ? ? ? ? ? ?return -1; ? ?} ? ?return 0; }/** @brief 給服務(wù)器發(fā)送指令 * @param * @return 失敗返回-1/成功返回0 ? ?SIZE 返回等到的文件大小 */static int send_cmd(int ctrl_sock,eu_cmd_type typ, const char *val,const char *ack_num) { ? ?int ret =-1; ? ?char send_buf[MAX_BUF]={0}; ? ?char read_buf[MAX_BUF]={0}; ? ?char *pos= NULL; ? ?char tmp[64] ={0}; ? ?if((typ == CMD_USER) ||(typ == CMD_PASS) || (typ == CMD_CWD)){ ? ? ? ?if((val == NULL) ||(ack_num == NULL)){ ? ? ? ? ? ?printf("argc is NULL\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ?} ? ? ? ?switch(typ){ ? ?case CMD_USER: ? ? ? ?memset(send_buf,0,sizeof(send_buf)); ? ? ? ?sprintf(send_buf,"USER %s\r\n",val); ? ? ? ?ret = write(ctrl_sock,send_buf,strlen(send_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("write failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?memset(read_buf,0,sizeof(read_buf)); ? ? ? ?ret = read(ctrl_sock,read_buf,sizeof(read_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("read failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?ret = strncmp(read_buf,ack_num,strlen(ack_num)); ? ? ? ?break; ? ?case CMD_PASS: ? ? ? ?memset(send_buf,0,sizeof(send_buf)); ? ? ? ?sprintf(send_buf,"PASS %s\r\n",val); ? ? ? ?ret = write(ctrl_sock,send_buf,strlen(send_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("write failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?memset(read_buf,0,sizeof(read_buf)); ? ? ? ?ret = read(ctrl_sock,read_buf,sizeof(read_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("read failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?ret = strncmp(read_buf,ack_num,strlen(ack_num)); ? ? ? ?break; ? ?case CMD_PASV: /*只發(fā)送命令,函數(shù)外面接收提取信息*/ ? ? ? ?memset(send_buf,0,sizeof(send_buf)); ? ? ? ?sprintf(send_buf,"PASV\r\n"); ? ? ? ?ret = write(ctrl_sock,send_buf,strlen(send_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("write failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?break; ? ?case CMD_CWD: ? ? ? ?memset(send_buf,0,sizeof(send_buf)); ? ? ? ?sprintf(send_buf,"CWD %s\r\n",val); ? ? ? ?ret = write(ctrl_sock,send_buf,strlen(send_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("write failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?usleep(500*1000); ? ? ? ?memset(read_buf,0,sizeof(read_buf)); ? ? ? ?ret = read(ctrl_sock,read_buf,sizeof(read_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("read failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?ret = strncmp(read_buf,ack_num,strlen(ack_num)); ? ? ? ?break; ? ?case CMD_QUIT: ? ? ? ?memset(send_buf,0,sizeof(send_buf)); ? ? ? ?sprintf(send_buf,"QUIT\r\n"); ? ? ? ?ret = write(ctrl_sock,send_buf,strlen(send_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("write failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?usleep(500*1000); ? ? ? ?memset(read_buf,0,sizeof(read_buf)); ? ? ? ?ret = read(ctrl_sock,read_buf,sizeof(read_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("read failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ?// ? ?ret = strncmp(read_buf,ack_num,strlen(ack_num)); ? ?case CMD_LIST: ? ? ? ?memset(send_buf,0,sizeof(send_buf)); ? ? ? ?sprintf(send_buf,"LIST %s\r\n",val); ? ? ? ?ret = write(ctrl_sock,send_buf,strlen(send_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("write failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?memset(read_buf,0,sizeof(read_buf)); ? ? ? ?usleep(100*1000); /*等待一會把266 也接收回來*/ ? ? ? ?ret = read(ctrl_sock,read_buf,sizeof(send_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("read failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ?// ? ?ret = strncmp(read_buf,ack_num,strlen(ack_num)); ? ? ? ?break; ? ?case CMD_STOR: ? ? ? ?memset(send_buf,0,sizeof(send_buf)); ? ? ? ?sprintf(send_buf,"STOR %s\r\n",val); ? ? ? ?ret = write(ctrl_sock,send_buf,strlen(send_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("write failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?usleep(50*1000); ? ? ? ?memset(read_buf,0,sizeof(read_buf)); ? ? ? ?ret = read(ctrl_sock,read_buf,sizeof(read_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("read failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ?// ? ?ret = strncmp(read_buf,ack_num,strlen(ack_num)); ? ? ? ?break; ? ?case CMD_RETR: ? ? ? ?memset(send_buf,0,sizeof(send_buf)); ? ? ? ?sprintf(send_buf,"RETR %s\r\n",val); ? ? ? ?ret = write(ctrl_sock,send_buf,strlen(send_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("write failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?usleep(50*1000); ? ? ? ?memset(read_buf,0,sizeof(read_buf)); ? ? ? ?ret = read(ctrl_sock,read_buf,sizeof(read_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("read failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ?// ? ?ret = strncmp(read_buf,ack_num,strlen(ack_num)); ? ? ? ?break; ? ?case CMD_SIZE_FTP: ? ? ? ?memset(send_buf,0,sizeof(send_buf)); ? ? ? ?sprintf(send_buf,"SIZE %s\r\n",val); ? ? ? ?ret = write(ctrl_sock,send_buf,strlen(send_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("write failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?usleep(50*1000); ? ? ? ?memset(read_buf,0,sizeof(read_buf)); ? ? ? ?ret = read(ctrl_sock,read_buf,sizeof(read_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("read failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?/* 客戶端接收服務(wù)器的響應(yīng)碼和信息,正常為 ”213 <size>” */ ? ? ? ?pos = strstr(read_buf,ack_num); ? ? ? ?if(pos != NULL){ ? ? ? ? ? ?pos += strlen(ack_num) +1; ? ? ? ? ? ?strcpy(tmp,pos); ? ? ? ? ? ?ret = atoi(tmp); ? ? ? ?} ? ? ? ?else{ ? ? ? ? ? ?ret =-1; ? ? ? ?} ? ? ? ? ? ? ? ?break; ? ? ? ?case CMD_PORT_FTP: ? ? ? ?memset(send_buf,0,sizeof(send_buf)); ? ? ? ?sprintf(send_buf,"PORT %s\r\n",val); ? ? ? ?ret = write(ctrl_sock,send_buf,strlen(send_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("write failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?usleep(50*1000); ? ? ? ?memset(read_buf,0,sizeof(read_buf)); ? ? ? ?ret = read(ctrl_sock,read_buf,sizeof(read_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("read failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?ret = strncmp(read_buf,ack_num,strlen(ack_num)); ? ? ? ?break; ? ? ? ?case CMD_MLSD: ? ? ? ?memset(send_buf,0,sizeof(send_buf)); ? ? ? ?sprintf(send_buf,"MLSD\r\n"); ? ? ? ?ret = write(ctrl_sock,send_buf,strlen(send_buf)); ? ? ? ?if(ret < 0){ ? ? ? ? ? ?printf("write failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?break; ? ?default:break; ? ?} ? ?printf("FTP server ack= %s\n",read_buf); ? ? ? ?return ret; }/** @brief 進入主動模式,讓服務(wù)器主動連接到客戶端的端口 * @param 無 * @return -1/成功返回client_server_sock*/static int enter_active_mode(int ctrl_sock) { ? ?int data_sock,server_sock; ? ?struct sockaddr_in name; ? ?struct sockaddr_in client_name,loc_addr; ? ?unsigned short server_port =0; ? ?int ret =-1; ? ?int len =0; ? ?char send_buf[64] ={0}; ? ?char ip[20]={0}; ? ?unsigned short ?ip0,ip1,ip2,ip3,p1,p2; ? ?//char read_buf[128] ={0}; ? ?struct timeval tv_out; ? ?/*設(shè)置sock fd 接收超時時間*/ ? ?tv_out.tv_sec =3; ? ?tv_out.tv_usec =0; ?/* ? ?if(GetAddr("eth0", ip, SIOCGIFADDR) != 0) ? ?{ ? ? ? ? ? ? printf("get local ip failed\n"); ? ? ? ?return -1; ? ?} ? ?printf("local ip =%s\n",ip); ? ?*/ ? ?memset(&name,0,sizeof(name)); ? ?memset(&client_name,0,sizeof(client_name)); ? ?/*通過ctrl_sock獲取到本機的ip*/ ? ?len =sizeof(name); ? ?if(getsockname(ctrl_sock,(struct sockaddr*)&name,&len) == -1) ? ?{ ? ? ? ?printf("get sock name failed\n"); ? ? ? ?return -1; ? ?} ? ? ? ?sscanf(inet_ntoa(name.sin_addr),"%hu.%hu.%hu.%hu",&ip0,&ip1,&ip2,&ip3); ? ? ? ? ? ?server_sock = socket(AF_INET,SOCK_STREAM,0); ? ?if(server_sock <0){ ? ? ? ?printf("get sock failed\n"); ? ? ? ?return -1; ? ?} ? ?/*設(shè)置接收超時*/ ? ?setsockopt(server_sock, SOL_SOCKET, SO_RCVTIMEO,&tv_out,sizeof(tv_out)); ? ? ? ?name.sin_family = AF_INET; ? ?name.sin_port = 0; ? ?len = sizeof(name); ? ?ret = bind(server_sock,(struct sockaddr *)&name,len); ? ?if(ret < 0){ ? ? ? ?printf("bind error\n"); ? ? ? ?goto err0; ? ?} ? ? ? ?/*通過ctrl_sock獲取到系統(tǒng)分配到的端口*/ ? ?len = sizeof(loc_addr); ? ?memset(&loc_addr,0,len); ? ?ret = getsockname(server_sock,(struct sockaddr *)&loc_addr,&len); ? ?if(ret < 0) ? ?{ ? ? ? ?printf("get sock name failed\n"); ? ? ? ?goto err0; ? ?} ? ?server_port = ntohs(loc_addr.sin_port); ? ?p1 = server_port/256; ? ?p2 = server_port%256; ? ?ret = listen(server_sock,10); ? ?if(ret < 0) ? ?{ ? ? ? ?printf("listen error\n"); ? ? ? ?goto err0; ? ?} ? ?/*給服務(wù)器 命令 “PORT ? ? ? \r\n*/ ? ?/*將ip中的.更換為,*/#if 0 ? ? ? ?&ip0 = strtok(ip,"."); ? ?&ip1 = strtok(NULL,"."); ? ?&ip2 = strtok(NULL,"."); ? ?&ip3 = strtok(NULL,".");#endif ? ?sprintf(send_buf,"%hu,%hu,%hu,%hu,%hu,%hu",ip0,ip1,ip2,ip3,p1,p2); ? ?printf("send_buf =%s server_port=%d\n",send_buf,server_port); ? ?ret = send_cmd(ctrl_sock,CMD_PORT_FTP, send_buf,ACK_PORT_NUM); ? ?if(ret < 0){ ? ? ? ?printf("Send PORT failed\n"); ? ? ? ?goto err0; ? ?} ? ?return server_sock; err0: ? ?close(server_sock); ? ?return -1; }/** @brief 進入被動模式,讓服務(wù)器在數(shù)據(jù)端口監(jiān)聽數(shù)據(jù) * @param 無 * @return -1/成功返回0*/static int enter_passive_mode(int ctrl_sock,char *data_ip, int * data_port) { ? ?int ret =-1; ? ?char read_buf[MAX_BUF]={0}; ? ?char tmp_buf[64]={0}; ? ?unsigned char ip1,ip2,ip3,ip4,port1,port2; ? ?//char *tmp; ? ?if((data_ip == NULL) ||(data_port == NULL)){ ? ? ? ?printf("argc is NULL\n"); ? ? ? ?return -1; ? ?} ? ?ret = send_cmd(ctrl_sock,CMD_PASV,NULL,NULL); ? ?if(ret < 0){ ? ? ? ? ? ?printf("send_cmd ?%d failed \n",CMD_PASV); ? ? ? ? ? ?return -1; ? ?} ? ?usleep(100*1000); ? ?ret = read(ctrl_sock,read_buf,sizeof(read_buf)); ? ?if(ret < 0){ ? ? ? ?printf("read failed\n"); ? ? ? ?return -1; ? ?} ? ?printf("rev =%d: %s\n",ret,read_buf); ? ?if(strstr(read_buf,ACK_PASV_NUM) != NULL){ ? ? ? ? ? ? ? ?sscanf(strchr(read_buf,'(')+1,"%hhu,%hhu,%hhu,%hhu,%hhu,%hhu",&ip1,&ip2,&ip3,&ip4,&port1,&port2); ? ? ? ?//printf("ip1=%d,ip2=%d,ip3=%d,ip4=%d,port1 =%d ,port2 = %d\n",ip1,ip2,ip3,ip4,port1,port2); ? ? ? ? ? ? ? ?//snprintf(data_ip,sizeof(data_ip),"%hhu,%hhu,%hhu,%hhu",ip1,ip2,ip3,ip4); ? ? ? ?//memset(data_ip,0,sizeof(data_ip)); ? ? ? ?//snprintf(data_ip,sizeof(data_ip),"%d.%d.%d.%d",ip1,ip2,ip3,ip4); ? ? ? ?//printf("data_ip = %s\n",data_ip); ? ? ? ?memset(data_ip,0,sizeof(data_ip)); ? ? ? ?memset(tmp_buf,0,sizeof(tmp_buf)); ? ? ? ?itoa(ip1,tmp_buf,10); ? ? ? ?strcat(data_ip,tmp_buf); ? ? ? ?strcat(data_ip,"."); ? ? ? ? ? ? ? ?memset(tmp_buf,0,sizeof(tmp_buf)); ? ? ? ?itoa(ip2,tmp_buf,10); ? ? ? ?strcat(data_ip,tmp_buf); ? ? ? ?strcat(data_ip,"."); ? ? ? ?memset(tmp_buf,0,sizeof(tmp_buf)); ? ? ? ?itoa(ip3,tmp_buf,10); ? ? ? ?strcat(data_ip,tmp_buf); ? ? ? ?strcat(data_ip,"."); ? ? ? ?memset(tmp_buf,0,sizeof(tmp_buf)); ? ? ? ?itoa(ip4,tmp_buf,10); ? ? ? ?strcat(data_ip,tmp_buf); ? ? ? ?//printf("data_ip1 = %s\n",data_ip); ? ? ? ? ? ?*data_port = port1*256+port2; ? ? ? ? ? ?} ? ?return 0; }/** @brief 從ftp服務(wù)器上下載文件 * @param ?ctrl_sock 控制服務(wù)器sock ?connect_mode= 0 設(shè)置服務(wù)器被動模式下載,非0服務(wù)器主動模式下載 ?server_filepath_name 要下載文件的路徑 ?newfilename 下載到本地的路徑和文件名字 ?offset 設(shè)置下載文件偏移的位置,不偏移寫0 ,可用于錯誤時續(xù)傳。 * @return -1/成功返回未接收到的字節(jié)數(shù)*/int down_file_ftpserver(int ctrl_sock, char *server_filepath_name,const ?char *newfilename,int connect_mode,int offset,eu_cmd_type typ) { ? ? ? ?int ret =-1,file_size=0; ? ?char rec_buf[2048] ={0}; ? ?char stri[128]={0}; ? ?int read_size =0; ? ?char * pos =NULL; ? ?char *tmp = NULL; ? ?int flags =O_CREAT|O_RDWR|O_TRUNC;; ? ? ? ?close_st_info(&server_info); ? ?if(server_filepath_name == NULL ?|| newfilename == NULL){ ? ? ? ?printf("argc is NULL\n"); ? ? ? ?return -1; ? ?} ? ? ? ?/*提取出server_path file name*/ ? ?tmp = server_filepath_name; ? ?if(tmp != NULL){ ? ? ? ?while(tmp != NULL){ ? ? ? ? ? ? ? ?tmp = strstr(tmp,"/"); ? ? ? ?// ? ?printf("tmp =%x :%s\n",tmp,tmp); ? ? ? ? ? ?if(tmp != NULL){ ? ? ? ? ? ? ? ?pos = tmp; ? ? ? ? ? ? ? ?tmp++; /*越過找到的"/"*/ ? ? ? ? ? ?} ? ? ? ?} ? ? ? ?if(pos !=NULL){ ? ? ? ? ? ?strncpy(server_info.server_path,server_filepath_name,pos-server_filepath_name+1); ? ? ? ? ? ?strcpy(server_info.server_filename,pos+1); ? ? ? ?} ? ? ? ?else{ ? ? ? ? ? ? ? ?strcpy(server_info.server_filename,server_filepath_name); ? ? ? ?} ? ?} ? ?printf("server path = %s ;file name =%s\n",server_info.server_path,server_info.server_filename); ? ?if((typ !=CMD_RETR) && (typ !=CMD_LIST)){ ? ? ? ?printf("typ value is not CMD_RETR or CMD_LIST\n"); ? ? ? ?return -1; ? ? ? ?} ? ?if(connect_mode){ /*主動模式*/ ? ? ? ? ? ?server_info.client_server_sock =enter_active_mode(ctrl_sock); ? ? ? ?if(server_info.client_server_sock< 0) ? ? ? ?{ ? ? ? ? ? ?printf("get data_scok failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ?}else{ /*被動模式*/ ? ? ? ?ret = enter_passive_mode(ctrl_sock,server_info.data_ip, &server_info.data_port); ? ? ? ?if(ret < 0){ ? ? ? ? ? ? ? ?printf("set passive mode failed\n"); ? ? ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?printf("server_info.data_ip =%s, data_port =%d \n",server_info.data_ip,server_info.data_port); ? ? ? ?server_info.data_sock = get_data_sock(server_info.data_ip,server_info.data_port); ? ? ? ?if(server_info.data_sock < 0){ ? ? ? ? ? ?printf("get data sock failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ?} ? ?/*更改目錄*/ ? ? ?if(strlen(server_info.server_path) !=0) ? ? ?{ ? ? ? ? ret = ?send_cmd(ctrl_sock,CMD_CWD,server_info.server_path,ACK_CWD_NUM); ? ? ? ? if(ret < 0){ ? ? ? ? ? ? ? ?printf("set passive mode failed\n"); ? ? ? ? ? ? ? ?goto err0; ? ? ? ? } ? ? ?} ? ? ? ? ? if(typ ==CMD_RETR){/*發(fā)送下載文件命令*/ ? ? ? ? /*設(shè)置下載文件偏移的位置*/ ? ? ? ? if(offset >0){ ? ? ? ? ? ? ? ? ? ? flags =O_CREAT|O_RDWR|O_APPEND; ? ? ? ? ? ? ? ? ?itoa(offset,stri,10); ? ? ? ? ? ? ret = ? ?send_cmd(ctrl_sock,CMD_REST,stri,ACK_REST_NUM); ? ? ? ? ? ? ?if(ret < 0){ ? ? ? ? ? ? ? ? ? ? printf("set file offsize failed\n"); ? ? ? ? ? ? ? ? ? ? goto err0; ? ? ? ? ? ? ?} ? ? ? ? ? } ? ? ? ? ret = ?send_cmd(ctrl_sock,CMD_RETR,server_info.server_filename,ACK_RETR_NUM); ? ? ? ? if(ret < 0){ ? ? ? ? ? ? ? ?printf("send RETR failed\n"); ? ? ? ? ? ? ? ?goto err0; ? ? ? ? } ? ? } ? ?else if(typ ==CMD_LIST){ ? ? ? ? ret = ?send_cmd(ctrl_sock,CMD_LIST,server_filepath_name,ACK_LIST_NUM); ? ? ? ? if(ret < 0){ ? ? ? ? ? ? ? ?printf("send LIST failed\n"); ? ? ? ? ? ? ? ?goto err0; ? ? ? ? } ? ? } ? ?if(connect_mode){ ? ? ? ?server_info.data_sock= get_active_data_sock(server_info.client_server_sock); ? ? ? ?if(server_info.data_sock <0) ? ? ? ?{ ? ? ? ? ? ?printf("accept failed\n"); ? ? ? ? ? ?goto err0; ? ? ? ?} ? ?} ? ? ?server_info.file_handle = open(newfilename,flags,0766); ? ? if(server_info.file_handle < 0){ ? ? ? ?printf("open file failed\n"); ? ? ? ? ? ?goto err0; ? ? } ? ? if(offset >0){ ? ? ? ? lseek(server_info.file_handle,offset, SEEK_SET); ? ? ? ? read_size += offset; ? ? } ? ? ? ? for(;;){ ? ? ? ? memset(rec_buf,0,sizeof(rec_buf)); ? ? ? ? ? ? ? ?ret = recv(server_info.data_sock,rec_buf,sizeof(rec_buf),0); ? ? ? ? if(ret < 0) ? ? ? ? { ? ? ? ? ? ?printf("Read error\n"); ? ? ? ? ? ?goto err1; ? ? ? ?} ? ? ? ?else if(ret == 0) ? ? ? ?{ ? ? ? ? ? ?ret = read_size; ? ? ? ? ? ?goto err1; ? ? ? ?} ? ? ? ?else if(ret >0) ? ? ? ?{ ? ? ? ? ? ?read_size += ret; ? ? ? ? ? ?ret = write(server_info.file_handle,rec_buf,ret); ? ? ? ? ? ?if(ret < 0) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?printf("Write error\n"); ? ? ? ? ? ? ? ?goto err1; ? ? ? ? ? ?} ? ? ? ? ? ?//printf("read_buf =%s\n",rec_buf); ? ? ? ?} ? ? ? ? } ? ? err1: ? ?if(server_info.file_handle >0) ? ? ? ?close(server_info.file_handle); err0: ? ?if(server_info.client_server_sock > 0) ? ? ? ?close(server_info.client_server_sock); ? ?if(server_info.data_sock > 0) ? ? ? ?close(server_info.data_sock); ? ?memset(rec_buf,0,sizeof(rec_buf)); ? ?/* 客戶端接收服務(wù)器的響應(yīng)碼和信息,正常為 ”226 Transfer complete.” */ ? ?read(ctrl_sock,rec_buf,sizeof(rec_buf)); /*有時消息再發(fā)送完命令后里面就能收到,導(dǎo)致會阻塞在這個上面*/ ? ?printf("%s \n Download file end!!\n",rec_buf); ? ? ? ?return ret; ? ? }/** @brief 上傳文件從ftp服務(wù)器 * @param ?ctrl_sock 控制服務(wù)器sock ?connect_mode = 0 設(shè)置服務(wù)器被動模式,非0 服務(wù)器主動模式 ?server_filepath_name ?上傳到服務(wù)器上的文件路徑和名稱 ?srcfilename 本地要上傳的路徑和文件名字 ?offset 設(shè)置下載文件偏移的位置,不偏移寫0 ,可用于錯誤時續(xù)傳。 * @return -1/成功返回上傳完成的字節(jié)數(shù)*/int up_file_ftpserver(int ctrl_sock, char *server_filepath_name, ? ? ? ?const ?char *srcfilename,int connect_mode,int offset) { ? ?int ret =-1,file_size=0; ? ?int file_handle =0; ? ?char rec_buf[2048] ={0}; ? ?int read_size =0; ? ?char stri[128]={0}; ? ?char *tmp = NULL; ? ?char * pos =NULL; ? ?close_st_info(&server_info); ? ?if((server_filepath_name == NULL) ||(srcfilename == NULL)){ ? ? ? ?printf("argc is NULL\n"); ? ? ? ?return -1; ? ?} ? ? ? ?/*提取出server_path file name*/ ? ?tmp = server_filepath_name; ? ?if(tmp != NULL){ ? ? ? ?while(tmp != NULL){ ? ? ? ? ? ? ? ?tmp = strstr(tmp,"/"); ? ? ? ?// ? ?printf("tmp =%x :%s\n",tmp,tmp); ? ? ? ? ? ?if(tmp != NULL){ ? ? ? ? ? ? ? ?pos = tmp; ? ? ? ? ? ? ? ?tmp++; /*越過找到的"/"*/ ? ? ? ? ? ?} ? ? ? ?} ? ? ? ?if(pos !=NULL){ ? ? ? ? ? ?strncpy(server_info.server_path,server_filepath_name,pos-server_filepath_name+1); ? ? ? ? ? ?strcpy(server_info.server_filename,pos+1); ? ? ? ?} ? ? ? ?else{ ? ? ? ? ? ? ? ?strcpy(server_info.server_filename,server_filepath_name); ? ? ? ?} ? ?} ? ?printf("server path = %s ;file name =%s\n",server_info.server_path,server_info.server_filename); ? ?if(connect_mode){ /*主動模式*/ ? ? ? ? ? ? ? ?server_info.client_server_sock =enter_active_mode(ctrl_sock); ? ? ? ?if(server_info.client_server_sock <= 0) ? ? ? ?{ ? ? ? ? ? ?printf("get data_scok failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ? ? ?}else{ /*被動模式*/ ? ? ? ?ret = enter_passive_mode(ctrl_sock,server_info.data_ip, &server_info.data_port); ? ? ? ?if(ret < 0){ ? ? ? ? ? ? ? ?printf("set passive mode failed\n"); ? ? ? ? ? ? ? ?return -1; ? ? ? ?} ? ? ? ?printf("server_info.data_ip =%s, data_port =%d\n",server_info.data_ip,server_info.data_port); ? ? ? ?server_info.data_sock = ?get_data_sock(server_info.data_ip,server_info.data_port); ? ? ? ?if(server_info.data_sock < 0){ ? ? ? ? ? ?printf("get data sock failed\n"); ? ? ? ? ? ?return -1; ? ? ? ?} ? ?} ? ? /*更改目錄*/ ? ? ? if(strlen(server_info.server_path) !=0) ? ? ? { ? ? ? ? ?ret = ?send_cmd(ctrl_sock,CMD_CWD, server_info.server_path,ACK_CWD_NUM); ? ? ? ? ?if(ret < 0){ ? ? ? ? ? ? ? ? printf("set passive mode failed\n"); ? ? ? ? ? ? ? ? goto err0; ? ? ? ? ?} ? ? ? } ? ? /*設(shè)置上傳文件偏移的位置*/ ? ? if(offset >0){ ? ? ? ? ?itoa(offset,stri,10); ? ? ? ? ret = ? ?send_cmd(ctrl_sock,CMD_REST,stri,ACK_REST_NUM); ? ? ? ? ?if(ret < 0){ ? ? ? ? ? ? ? ? printf("set file offsize failed\n"); ? ? ? ? ? ? ? ? goto err0; ? ? ? ? ?} ? ? ? } ? ?/*發(fā)送上傳文件命令*/ ? ? ret = ?send_cmd(ctrl_sock,CMD_STOR,server_info.server_filename,ACK_STOR_NUM); ? ? if(ret < 0){ ? ? ? ? ? ?printf("send STOR failed\n"); ? ? ? ? ? ?goto err0; ? ? } ? ? ? ? if(connect_mode){ ? ? ? ?server_info.data_sock= get_active_data_sock(server_info.client_server_sock); ? ? ? ?if(server_info.data_sock <0) ? ? ? ?{ ? ? ? ? ? ?printf("accept failed\n"); ? ? ? ? ? ?goto err0; ? ? ? ?} ? ?} ? ? ? ? ? ? ? ?server_info.file_handle = open(srcfilename,O_RDONLY); ? ? if(server_info.file_handle < 0){ ? ? ? ?printf("open file failed\n"); ? ? ? ? ? ?goto err0; ? ? } ? ? if(offset >0){ ? ? ? ? lseek(server_info.file_handle,offset, SEEK_SET); ? ? ? ? read_size += offset; ? ? } ? ? ? ? for(;;){ ? ? ? ? memset(rec_buf,0,sizeof(rec_buf)); ? ? ? ?ret = read(server_info.file_handle,rec_buf,sizeof(rec_buf)); ? ? ? ? if(ret < 0) ? ? ? ? { ? ? ? ? ? ? printf("read file error\n"); ? ? ? ? ? ?goto err1; ? ? ? ?} ? ? ? ?else if(ret == 0) ? ? ? ?{ ? ? ? ? ? ?ret = read_size; ? ? ? ? ? ?goto err1; ? ? ? ?} ? ? ? ?else if(ret >0) ? ? ? ?{ ? ? ? ? ? ?//printf("read_buf =%s\n",rec_buf); ? ? ? ? ? ? ? ? ? ? ? ?ret = write(server_info.data_sock,rec_buf,ret); ? ? ? ? ? ?if(ret < 0) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ?printf("Write failed\n"); ? ? ? ? ? ? ? ? ? ?goto err1; ? ? ? ? ? ? ? ?}else{ ? ? ? ? ? ? ? ? ?read_size += ret; ? ? ? ? ? ? ? ?// lseek(file_handle,read_size, SEEK_SET); ? ? ? ? ? ?} ? ? ? ? ? ?} ? ? } err1: ? ?if(server_info.file_handle >0) ? ? ? ?close(server_info.file_handle); err0: ? ?if(server_info.client_server_sock > 0) ? ? ? ?close(server_info.client_server_sock); ? ?if(server_info.data_sock > 0) ? ? ? ?close(server_info.data_sock); ? ?memset(rec_buf,0,sizeof(rec_buf)); ? ?/* 客戶端接收服務(wù)器的響應(yīng)碼和信息,正常為 ”226 Transfer complete.” */ ? ?read(ctrl_sock,rec_buf,sizeof(rec_buf)); ? ?printf("%s\n Up file end!!!\n",rec_buf); ? ? ? ?return ret; ? ? }static int close_st_info(FTP_DATA_INFO * info) { ? ?if(info == NULL) ? ? ? ?return -1; ? ?if(info->file_handle >0) ? ? ? ?close(info->file_handle); ? ?if(info->client_server_sock > 0) ? ? ? ?close(info->file_handle); ? ?if(info->data_sock > 0) ? ? ? ?close(info->file_handle); ? ?memset(info,0,sizeof(FTP_DATA_INFO)); ? ?return 0; }int get_fsize_ftpserver(int ctrl_sock, char *server_filepath_name) { ? ?int ret =-1; ? ?if(server_filepath_name ==NULL){ ? ? ? ?printf("argc is null\n"); ? ? ? ?return -1; ? ?} ? ? ? ?/*發(fā)送上傳文件命令*/ ? ? ret = ?send_cmd(ctrl_sock,CMD_SIZE_FTP,server_filepath_name,ACK_SIZE_NUM); ? ? if(ret < 0){ ? ? ? ? ? ?printf("send SZIE failed\n"); ? ? ? ? ? ?return -1; ? ? } ? ?//printf("file size =%d\n",ret); ? ?return ret; }/** @brief 從ftp服務(wù)器退出 * @param ?ctrl_sock 控制服務(wù)器sock * @return -1/成功返回0*/int quit_fpt_server(int ctrl_sock) { ? ?int ret =-1; ? ?close_st_info(&server_info); ? ? ? ?ret = send_cmd(ctrl_sock,CMD_QUIT,NULL,ACK_QUIT_NUM); ? ?if(ret < 0) ? ? ? ?printf("quit fpt server error\n"); ? ?close(ctrl_sock); ? ? ? ?return ret; }

fpt.h

#ifndef __FTP_H__#define __FTP_H__#define FTP_SERVER_PORT 21typedef enum{ ? ?CMD_USER =0, /*用戶名*/ ? ?CMD_PASS, ? ?/*密碼*/ ? ?CMD_PASV, ? ?/*讓服務(wù)器進入被動模式*/ ? ?CMD_CWD, ? ? /*切換工作目錄*/ ? ?CMD_SIZE_FTP, ? ?/*獲取文件大小*/ ? ?CMD_RETR, ? ?/*下載文件*/ ? ?CMD_REST, ? ? ?/*指定下載文件的偏移量*/ ? ?CMD_QUIT, ? ? ?/*退出命令*/ ? ?CMD_LIST, ? ?/*列表*/ ? ?CMD_STOR, ? ?/*上傳文件*/ ? ? ? ?CMD_PORT_FTP,/*發(fā)送客戶端端口給服務(wù)器*/ ? ?CMD_MLSD, /*列表*/ ? ?}eu_cmd_type;int connect_ftp_server(const char* server_ip,const int port);int login_ftp_server(int ctrl_sock,const char *user_name, const char * passwd);int down_file_ftpserver(int ctrl_sock, char *server_filepath_name, ? ?const ?char *newfilename,int connect_mode,int offset,eu_cmd_type typ);int up_file_ftpserver(int ctrl_sock, char *server_filepath_name, ? ? ? ?const ?char *srcfilename,int connect_mode,int offset);int get_fsize_ftpserver(int ctrl_sock, char *server_filepath_name);int quit_fpt_server(int ctrl_sock);#endif

?

?

?

遇到的主要問題記錄:

  1、實現(xiàn)FTP主動模式的時候,開始的accpet一直無法接收到服務(wù)器的連接請求。

后來用wireshark跟蹤FileZilla與服務(wù)器直接的通信數(shù)據(jù)才找到問題所在。原來accept要在

必須要在LIST等下載上傳命令發(fā)送后服務(wù)器才會連接過來。

? ? ? 2、主要一定要關(guān)閉掉防火墻

? ? ? 3、ftp還有一些傳送方法類型的選擇,本代碼中并沒有進行設(shè)置,后續(xù)用到的時候再進行完善。

 ?4、 代碼中接收服務(wù)器回復(fù)的時候增加了不少延遲。后來我有在sock?上設(shè)置接收超時,延遲太多反正感覺不是太好。



FTP客戶端c代碼功能實現(xiàn)的評論 (共 條)

分享到微博請遵守國家法律
浦东新区| 蓝山县| 汝南县| 温宿县| 余庆县| 富蕴县| 栾川县| 青岛市| 会昌县| 屏山县| 米泉市| 南郑县| 德阳市| 宜川县| 自贡市| 信阳市| 合肥市| 会昌县| 金堂县| 斗六市| 蒲江县| 庆阳市| 中山市| 得荣县| 瑞昌市| 长兴县| 句容市| 舒兰市| 扬州市| 黎城县| 巴东县| 木里| 济源市| 县级市| 灯塔市| 大荔县| 长宁区| 南投县| 闸北区| 垣曲县| 泰宁县|