用C语言实现ftp客户端?

shengger 2007-06-06 11:26:46
用C语言实现ftp客户端?在服务器上下载图片。
...全文
1683 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
shengger 2007-06-13
  • 打赏
  • 举报
回复
妈的,问题解决了,APPE book2.txt \r\n
多了一个空格。
写程序一定要细心了。
shengger 2007-06-12
  • 打赏
  • 举报
回复
Serv-U FTP平台的信息,可以上传。

220 Serv-U FTP Server v6.3 for WinSock ready...

USER *****

PASS ******

331 User name okay, need password.

230 User logged in, proceed.

PWD

257 "/" is current directory.

REST 0

350 Restarting at 0. Send STORE or RETRIEVE.

PASV

227 Entering Passive Mode (192,168,1,15,200,175)

APPE book2.txt

150 Opening ASCII mode data connection for book2.txt.

226 Transfer complete.
shengger 2007-06-12
  • 打赏
  • 举报
回复
谢谢lovejklife(程序员怎么样才能发财呢??) 我们网上聊聊啊,msn : shengger@gmail.com
shengger 2007-06-12
  • 打赏
  • 举报
回复
用227会不会在后面的IP 或者 port中出现?

我现在看了一下,用sendcommand("SYST")发过去,返回都是UNIX,可能是FTP平台模式不同,真的不太清楚。
我怀疑是转输方式的问题,ASCII IMAGE binary ebcdic tenex等五种方式。是不是要注意这个?
lovejklife 2007-06-12
  • 打赏
  • 举报
回复
strstr(SendMsgBuff,"227 Entering Passive Mode"))
不太好,只要比较227就可以了
不同的FTPSERVER实现有不用
有的甚至连命令好都有不同的
lovejklife 2007-06-12
  • 打赏
  • 举报
回复
用227会不会在后面的IP 或者 port中出现?
会啊,只要比较前三个字符就可以了
shengger 2007-06-11
  • 打赏
  • 举报
回复
大家帮我分析一下,我上传文件已经成功了,但是显示的文件打不开,很奇怪的文件,文件名对,时间也正确,但是看属性大小为0 bytes,文件名为:book.txt,但是打不开,打开也为空。不知道上传文件时间出现什么问题。

send(PASV)
send(REST 0)
send(APPE book.txt)

int length = send(文件数据)
//length=466没有问题

clostsocket(s);//关闭数据传输的socket

收到File receive OK.)


过程如下:
//////////////////////////////////////
USER ******

PASS 123456

331 Please specify the password.

230 Login successful.

PWD

257 "/"

FEAT

211-Features:

EPRT

EPSV

MDTM

PASV

REST STREAM

SIZE

TVFS

211 End

PASV

227 Entering Passive Mode (192,168,1,254,200,174)

REST 0

350 Restart position accepted (0).

APPE book.txt

150 Ok to send data.

226 File receive OK.

500 OOPS: vsf_sysutil_recv_peek: no data //????

shengger 2007-06-11
  • 打赏
  • 举报
回复
实现了,只是平台的不同,我在公司服务器上就是显示为0,文件打不开。现在我在旁边的机器上建立server-U建立新的ftp服务器就可以传上去。哎。不知道平台之间的差异?
这是最新的代码。


#include<stdio.h>
#include<WINSOCK2.H>

#pragma comment(lib,"WS2_32.lib")

#define SENDRECVBUFFE (128)
#define FILEBUFF (32769)

int OpenControlChannel(char *serverhost,int serverport, char *serverpath);
int ftp_cmd(int sockfd, char *pcmd);
int login(SOCKET s, char *logininfo, int tmplen);
int RecvAnalysis(SOCKET s, char *SendMsgBuff);
int CreateSocketData(SOCKET s, char *SendMsgBuff);
int sendcommand(SOCKET s, const char *sendcmd);
int SendFileData(SOCKET s, char *SendMsgBuff);
int pasv_list(SOCKET s);

bool pasv_flag=false;

void main()
{
char serverhost[] = "192.168.1.15";
int serverport = 21;
char serverpath[] = "192.168.1.15\tanhs";
OpenControlChannel(serverhost, serverport, serverpath);

return;

}

// open the control channel to the FTP server
int OpenControlChannel(char *serverhost,int serverport, char *serverpath)
{
WSADATA wsaData;
WORD sockVersion=MAKEWORD(1,1);
WSAStartup(sockVersion,&wsaData);

SOCKET s=socket(AF_INET, SOCK_STREAM, 0);
if(s==INVALID_SOCKET)
{
printf(" Failed socket()\n");
WSACleanup();
return -1;
}

sockaddr_in servAddr;
servAddr.sin_family=AF_INET;
servAddr.sin_port=htons(serverport);
servAddr.sin_addr.S_un.S_addr = inet_addr(serverhost);

//client请求连接server, servAddr为远程主机IP地址和端口
if(connect(s, (sockaddr*)&servAddr, sizeof(servAddr))==SOCKET_ERROR)
{
printf("Failed connect()\n");
WSACleanup();
return -1;
}

char buff[128];
RecvAnalysis(s, buff);

// 读取配置信息
FILE *fp = fopen("D:\\ftp\\user.txt", "rt");
if (fp == NULL)
{
printf("can't open user.txt!\r\n");
return -1;
}
char username[32] = {0};
char password[32] = {0};
fscanf(fp, "%s", username);
fscanf(fp, "%s", password);
fclose(fp);

char tmp[SENDRECVBUFFE];
sprintf(tmp,"USER %s\r\nPASS %s\r\n", username, password);
int tmplen =strlen(tmp);
//登录
if (login(s, tmp, tmplen) == -1)
{
return -1;
}
RecvAnalysis(s, buff);

//PWD返回当前目录,大多数ftp客户端用来确认服务器还能响应(预防超时)
if (-1 == sendcommand(s, "PWD"))
{
return -1;
}
RecvAnalysis(s, buff);

if (-1 == sendcommand(s, "REST 0"))
{
return -1;
}
RecvAnalysis(s, buff);

//PASV传输模式,现在大多数FTP客户端使用的传输方式,等待返回传输数据端口
pasv_flag=true;
memset(buff, 0, SENDRECVBUFFE);
if (-1 == sendcommand(s, "PASV"))
{
return -1;
}
RecvAnalysis(s, buff);

closesocket(s);
WSACleanup();
return 0;
}

//建立数据传输socket
int CreateSocketData(SOCKET s, char *SendMsgBuff)
{
WSADATA wsaData;
WORD sockVersion=MAKEWORD(1,1);
WSAStartup(sockVersion,&wsaData);

SOCKET sdata=socket(AF_INET, SOCK_STREAM, 0);
if(sdata==INVALID_SOCKET)
{
printf(" Failed socket()\n");
WSACleanup();
return -1;
}

int a0, a1, a2, a3, p0, p1;
char *a,*p;
sockaddr_in data_addr;
if (sscanf(SendMsgBuff,"227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)",&a0, &a1, &a2, &a3, &p0, &p1) != 6)
{
printf("Passive mode address scan failure. Shouldn't happen!\n");
return -1;
}
printf("%d,%d,%d,%d,%d,%d\n",a0,a1,a2,a3,p0,p1);
data_addr.sin_family = AF_INET;
a = (char *)&data_addr.sin_addr.s_addr;
a[0] = a0 & 0xff;
a[1] = a1 & 0xff;
a[2] = a2 & 0xff;
a[3] = a3 & 0xff;
p = (char *)&data_addr.sin_port;
p[0] = p0 & 0xff;
p[1] = p1 & 0xff;

//client请求连接server, servAddr为远程主机IP地址和端口
if(connect(sdata, (sockaddr*)&data_addr, sizeof(data_addr))==SOCKET_ERROR)
{
printf("Failed connect()\n");
WSACleanup();
return -1;
}
return sdata;
}

//通过数据sokcet传送数据到服务器
int SendFileData(SOCKET s, char *SendMsgBuff)
{
SOCKET sdata = CreateSocketData(s, SendMsgBuff);
if (sdata<0)
{
printf("CreateSocketData Error!");
return -1;
}

//REST一般用于断点续传,其后跟着设置文件从开头的偏移量
memset(SendMsgBuff, 0, SENDRECVBUFFE);

if (-1 == sendcommand(s, "APPE E770.jpg"))
{
return -1;
}
RecvAnalysis(s, SendMsgBuff);

//发送文件
FILE *fp;
int readLen = 0;
if ((fp = fopen("D:\\E770.jpg", "rb")) == NULL)
{
printf( "Can't open file!\n" );
return -1;
}
char SendData[FILEBUFF];

while (!feof(fp))
{
readLen = fread(SendData, sizeof(char), FILEBUFF, fp);
send(sdata, SendData, readLen, 0);
fflush( fp);
}
fclose(fp);

closesocket(sdata);
return 0;
}

int login(SOCKET s, char *logininfo, int tmplen)
{
//登录
char SendMsgBuff[SENDRECVBUFFE];
memset(SendMsgBuff, 0, SENDRECVBUFFE);
int nsend=send(s, logininfo, tmplen, 0);

if(nsend== SOCKET_ERROR)
{
printf("Failed send()\n");
return -1;
}

if (-1 == RecvAnalysis(s, SendMsgBuff))
{
return -1;
}
return 0;
}

int RecvAnalysis(SOCKET s, char *SendMsgBuff)
{
int EndFlg=0;
char GetChar;
int tmpLen = 0;
int nRecv = 0;
memset(SendMsgBuff, 0, SENDRECVBUFFE);

while (1)
{
fd_set ReadS;
FD_ZERO(&ReadS);
FD_SET(s, &ReadS);
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 500;
int Ret = select(0, &ReadS, NULL, NULL, &timeout);
if (Ret == SOCKET_ERROR)
{
return Ret;
}
if (0 == Ret)
{
//没数据,状态不发生更新,跳出对这个Socket的操作
break;
}

//每次接收一个字节
nRecv=recv(s, &GetChar, 1, 0);
if (SOCKET_ERROR == nRecv)
{
//接收出现错误
return nRecv;
}
else if (0 == nRecv)
{
return SOCKET_ERROR;
}

SendMsgBuff[tmpLen++] = GetChar;

if ((GetChar == '\n') && (tmpLen >2))
{
//看是否接收数据的结尾
if (SendMsgBuff[tmpLen-2] == '\r')
{
EndFlg = 1;
}
}

}

if (EndFlg)
{
if (pasv_flag==true)
{
if (strstr(SendMsgBuff,"227 Entering Passive Mode"))
{
if (SendFileData(s, SendMsgBuff)==-1)
{
return -1;
}
}
}
}
if (!EndFlg)
{
//没有收完整
return -1;
}

return 0;
}

//发送命令到server
int sendcommand(SOCKET s, const char *sendcmd)
{
char tmp[128];
sprintf(tmp,"%s \r\n", sendcmd);
int tmplen =strlen(tmp);

int nsend=send(s, tmp, tmplen, 0);
if(nsend== SOCKET_ERROR)
{
printf("Failed send()\n");
return -1;
}
return 0;
}

shengger 2007-06-11
  • 打赏
  • 举报
回复
#include<stdio.h>
#include<WINSOCK2.H>

#pragma comment(lib,"WS2_32.lib")

#define SENDRECVBUFFE (128)
#define FILEBUFF (32769)

int OpenControlChannel(char *serverhost,int serverport, char *serverpath);
int ftp_cmd(int sockfd, char *pcmd);
int login(SOCKET s, char *logininfo, int tmplen);
int RecvAnalysis(SOCKET s, char *SendMsgBuff);
int CreateSocketData(SOCKET s, char *SendMsgBuff);
int sendcommand(SOCKET s, const char *sendcmd);
int SendFileData(SOCKET s, char *SendMsgBuff);
int pasv_list(SOCKET s);

bool pasv_flag=false;

void main()
{
char serverhost[] = "192.168.1.15";
int serverport = 21;
char serverpath[] = "192.168.1.15\tanhs";
OpenControlChannel(serverhost, serverport, serverpath);

return;

}

// open the control channel to the FTP server
int OpenControlChannel(char *serverhost,int serverport, char *serverpath)
{
WSADATA wsaData;
WORD sockVersion=MAKEWORD(1,1);
WSAStartup(sockVersion,&wsaData);

SOCKET s=socket(AF_INET, SOCK_STREAM, 0);
if(s==INVALID_SOCKET)
{
printf(" Failed socket()\n");
WSACleanup();
return -1;
}

sockaddr_in servAddr;
servAddr.sin_family=AF_INET;
servAddr.sin_port=htons(serverport);
servAddr.sin_addr.S_un.S_addr = inet_addr(serverhost);

//client请求连接server, servAddr为远程主机IP地址和端口
if(connect(s, (sockaddr*)&servAddr, sizeof(servAddr))==SOCKET_ERROR)
{
printf("Failed connect()\n");
WSACleanup();
return -1;
}

char buff[128];
RecvAnalysis(s, buff);

// 读取配置信息
FILE *fp = fopen("D:\\ftp\\user.txt", "rt");
if (fp == NULL)
{
printf("can't open user.txt!\r\n");
return -1;
}
char username[32] = {0};
char password[32] = {0};
fscanf(fp, "%s", username);
fscanf(fp, "%s", password);
fclose(fp);

char tmp[SENDRECVBUFFE];
sprintf(tmp,"USER %s\r\nPASS %s\r\n", username, password);
int tmplen =strlen(tmp);
//登录
if (login(s, tmp, tmplen) == -1)
{
return -1;
}
RecvAnalysis(s, buff);

//PWD返回当前目录,大多数ftp客户端用来确认服务器还能响应(预防超时)
if (-1 == sendcommand(s, "PWD"))
{
return -1;
}
RecvAnalysis(s, buff);

//FEAT请求FTP服务器列出它的所有的扩展命令与扩展功能的
//if (-1 == sendcommand(s, "FEAT"))
//{
// return -1;
//}
RecvAnalysis(s, buff);
if (-1 == sendcommand(s, "REST 0"))
{
return -1;
}
RecvAnalysis(s, buff);

//LIST
pasv_list(s);

//PASV传输模式,现在大多数FTP客户端使用的传输方式,等待返回传输数据端口
pasv_flag=true;
memset(buff, 0, SENDRECVBUFFE);
if (-1 == sendcommand(s, "PASV"))
{
return -1;
}
RecvAnalysis(s, buff);

closesocket(s);
WSACleanup();
return 0;
}

//建立数据传输socket
int CreateSocketData(SOCKET s, char *SendMsgBuff)
{
WSADATA wsaData;
WORD sockVersion=MAKEWORD(1,1);
WSAStartup(sockVersion,&wsaData);

SOCKET sdata=socket(AF_INET, SOCK_STREAM, 0);
if(sdata==INVALID_SOCKET)
{
printf(" Failed socket()\n");
WSACleanup();
return -1;
}

int a0, a1, a2, a3, p0, p1;
char *a,*p;
sockaddr_in data_addr;
if (sscanf(SendMsgBuff,"227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)",&a0, &a1, &a2, &a3, &p0, &p1) != 6)
{
printf("Passive mode address scan failure. Shouldn't happen!\n");
return -1;
}
printf("%d,%d,%d,%d,%d,%d\n",a0,a1,a2,a3,p0,p1);
data_addr.sin_family = AF_INET;
a = (char *)&data_addr.sin_addr.s_addr;
a[0] = a0 & 0xff;
a[1] = a1 & 0xff;
a[2] = a2 & 0xff;
a[3] = a3 & 0xff;
p = (char *)&data_addr.sin_port;
p[0] = p0 & 0xff;
p[1] = p1 & 0xff;

//client请求连接server, servAddr为远程主机IP地址和端口
if(connect(sdata, (sockaddr*)&data_addr, sizeof(data_addr))==SOCKET_ERROR)
{
printf("Failed connect()\n");
WSACleanup();
return -1;
}
return sdata;
}

//通过数据sokcet传送数据到服务器
int SendFileData(SOCKET s, char *SendMsgBuff)
{
SOCKET sdata = CreateSocketData(s, SendMsgBuff);
if (sdata<0)
{
printf("CreateSocketData Error!");
return -1;
}

//REST一般用于断点续传,其后跟着设置文件从开头的偏移量
memset(SendMsgBuff, 0, SENDRECVBUFFE);

if (-1 == sendcommand(s, "APPE 000.txt"))
{
return -1;
}
RecvAnalysis(s, SendMsgBuff);

//发送文件
FILE *fp;
int readLen = 0;
if ((fp = fopen("D:\\book2.txt", "rb")) == NULL)
{
printf( "Can't open file!\n" );
return -1;
}
char SendData[FILEBUFF];

while (!feof(fp))
{
readLen = fread(SendData, sizeof(char), FILEBUFF, fp);
send(sdata, SendData, readLen, 0);
fflush( fp);
}
fclose(fp);

closesocket(sdata);

RecvAnalysis(s, SendMsgBuff);
printf("%s",SendMsgBuff);

return 0;
}

int login(SOCKET s, char *logininfo, int tmplen)
{
//登录
char SendMsgBuff[SENDRECVBUFFE];
memset(SendMsgBuff, 0, SENDRECVBUFFE);
//int nsend=send(s, logininfo, tmplen, 0);

int nsend = send(s, "USER tanhs\r\n",12,0);
//nsend = send(s, "PASS \r\n",6,0);
if(nsend== SOCKET_ERROR)
{
printf("Failed send()\n");
return -1;
}

if (-1 == RecvAnalysis(s, SendMsgBuff))
{
return -1;
}
return 0;
}

int RecvAnalysis(SOCKET s, char *SendMsgBuff)
{
int EndFlg=0;
char GetChar;
int tmpLen = 0;
int nRecv = 0;
memset(SendMsgBuff, 0, SENDRECVBUFFE);

while (1)
{
fd_set ReadS;
FD_ZERO(&ReadS);
FD_SET(s, &ReadS);
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 500;
int Ret = select(0, &ReadS, NULL, NULL, &timeout);
if (Ret == SOCKET_ERROR)
{
return Ret;
}
if (0 == Ret)
{
//没数据,状态不发生更新,跳出对这个Socket的操作
break;
}

//每次接收一个字节
nRecv=recv(s, &GetChar, 1, 0);
if (SOCKET_ERROR == nRecv)
{
//接收出现错误
return nRecv;
}
else if (0 == nRecv)
{
return SOCKET_ERROR;
}

SendMsgBuff[tmpLen++] = GetChar;

if ((GetChar == '\n') && (tmpLen >2))
{
//看是否接收数据的结尾
if (SendMsgBuff[tmpLen-2] == '\r')
{
EndFlg = 1;
}
}

}

if (EndFlg)
{
if (pasv_flag==true)
{
if (strstr(SendMsgBuff,"227 Entering Passive Mode"))
{
if (SendFileData(s, SendMsgBuff)==-1)
{
return -1;
}
}
}
}
if (!EndFlg)
{
//没有收完整
return -1;
}

return 0;
}

//发送命令到server
int sendcommand(SOCKET s, const char *sendcmd)
{
char tmp[128];
sprintf(tmp,"%s \r\n", sendcmd);
int tmplen =strlen(tmp);

int nsend=send(s, tmp, tmplen, 0);
if(nsend== SOCKET_ERROR)
{
printf("Failed send()\n");
return -1;
}
return 0;
}

int pasv_list(SOCKET s)
{
pasv_flag = false;
char buff[SENDRECVBUFFE];
memset(buff, 0, SENDRECVBUFFE);

if(-1==sendcommand(s, "PASV"))
{
printf("pasv_list sendcommand PASV ERROR!");
return -1;
}
RecvAnalysis(s, buff);

SOCKET sdata = CreateSocketData(s, buff);
if (sdata<0)
{
printf("CreateSocketData Error!");
return -1;
}
closesocket(sdata);

if(-1==sendcommand(s, "LIST"))
{
printf("pasv_list sendcommand LIST ERROR!");
return -1;
}
RecvAnalysis(s, buff);
return 0;

}
lovejklife 2007-06-11
  • 打赏
  • 举报
回复
代码贴出来吧
lovejklife 2007-06-11
  • 打赏
  • 举报
回复
看属性大小为0 bytes,很可能没传数据只是发了传输命令
shengger 2007-06-07
  • 打赏
  • 举报
回复
Ftp服务器提供了一个21port,专门来ftp控制.
shengger 2007-06-07
  • 打赏
  • 举报
回复
http://source.winehq.org/source/dlls/wininet/ftp.c
用的是WINAPI,在纯C中怎么行。socket看了一点,就是网络API,在学Unix 网络编程。
kf701 2007-06-06
  • 打赏
  • 举报
回复
server端怎么知道我请求连接,是否还要SOCKET写个server服务器?

从这句看出来你一定不会网络编程 。。。


shengger 2007-06-06
  • 打赏
  • 举报
回复
jixingzhong:thank you very much.i'll try it
jixingzhong 2007-06-06
  • 打赏
  • 举报
回复
unix FTP 程序(C语言编写):
http://www.cnblogs.com/maxwolf/archive/2006/05/31/414227.html

包括了 服务器程序和客户端程序,
楼主自己看看吧。
shengger 2007-06-06
  • 打赏
  • 举报
回复
哪位大哥帮个忙。
我的想法:
1,CLIENT建立一个命令控制SOCKET,用于传输FTP 命令,然后connect .
server端怎么知道我请求连接,是否还要SOCKET写个server服务器?

shengger 2007-06-06
  • 打赏
  • 举报
回复
哪位大哥帮个忙。
我的想法:
1,CLIENT建立一个命令控制SOCKET,用于传输FTP 命令,
2,用这个SOCKET连接到某个FTP SERVER
3,在这个命令控制SOCKET发送一系列命令:USER PASS TYPE CWD等等
4,然后根据配置参数来建立数据连接SOCKET
huashizhixin 2007-06-06
  • 打赏
  • 举报
回复
ding
GeomaticMm 2007-06-06
  • 打赏
  • 举报
回复
http://source.winehq.org/source/dlls/wininet/ftp.c
这是FTP的源程序 囊括了FTP的所有操作 并且没种都有两个版本
至于SOCKET 现在还没学呢 具体也不懂 放假准备才开始C的串口编程呢
希望对你有帮助
加载更多回复(3)

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧