Linux下socket编程之实现FTP client

体验了下Linux下的socket编程,实现了一个简单的FTP client,以二进制方式从服务器下载文件。

需要了解的知识:FTP协议、socket的常用函数

参考资料:
linux下socket编程实例
使用 Socket 通信实现 FTP 客户端程序
Linux Socket编程(不限Linux)
Linux socket 编程,第一部分
Linux socket 编程,第二部分

FTP client实现代码:

 

#include 
#include 
#include 
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include 

u_char LocalIP[16] = {0};   //本地IP
u_char FtpUser[16] = {0};
u_char FtpPass[16] = {0};
u_char FileName[] = {"3.bin"};
char buffer[1024]={0};   
char data_buffer[2048] = {0};
int control_sock;
int data_sock;

u_char FTP_send_cmd(int fd, u_char *pCMD,u_char *pPara,u_char *pResp);
u_short FTP_pasv_mode(void);

int main()
{
	int recbytes;
	int sin_size;
	struct sockaddr_in s_add,c_add;
	u_short portnum=21;//6800; 
	int len = 0;
	u_int FileSize = 0;
	u_long DataSize = 0;
	int i = 0;
	FILE *FPtr;
	u_short Percent = 0;		//接收到的百分比
	struct hostent *hp;
	u_char ServerAddr[40] = {0};		//服务器地址,可以输入IP或者域名
	u_char HostIP[16] = {0};			//服务器IP

	printf("Hello,welcome to client !\r\n");
	printf("Please enter server addr:\r\n");

	//从域名、主机名、IP得到IP地址
	scanf("%s",ServerAddr);
	getchar();
	if((hp = gethostbyname(ServerAddr))==NULL)
	{
		printf("cannot get IP from:%s\r\n",ServerAddr);
		exit(1);
	}
	strcpy(HostIP,(const char *)inet_ntoa(*((struct in_addr *)hp->h_addr)));
	printf("HostName :%s\n",hp->h_name);
	printf("IP Address :%s\n",HostIP);

	//申请控制流socket
	control_sock = socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == control_sock)
	{
		printf("socket fail ! \r\n");
		return -1;
	}
	printf("socket ok !\r\n");

	//建立控制连接
	bzero(&s_add,sizeof(struct sockaddr_in));
	s_add.sin_addr.s_addr= inet_addr(inet_ntoa(*((struct in_addr *)hp->h_addr)));//("127.0.0.1");
	s_add.sin_family=AF_INET;
	s_add.sin_port=htons(portnum);
	printf("s_addr = %#x ,port : %#x\r\n",s_add.sin_addr.s_addr,s_add.sin_port);	
	if(-1 == connect(control_sock,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
	{
	  printf("connect fail !\r\n");
	  return -1;
	}
	printf("connect ok !\r\n");

	//读取欢迎信息
	if(-1 == (recbytes = read(control_sock,buffer,1024)))
	{
	  printf("read data fail !\r\n");
	  return -1;
	}
	printf("read ok\r\nREC:\r\n");
	buffer[recbytes]='\0';
	printf("%s\r\n",buffer);

	//登录服务器
	printf("Please enter user name\r\n");
	scanf("%s",FtpUser);
	getchar();
	if (FTP_send_cmd(control_sock,"USER ",FtpUser,"331") != 0)
	{
		printf("submit user name error");
		return 0;
	}
	printf("Please enter pass word\r\n");
	scanf("%s",FtpPass);
	getchar();
	if (FTP_send_cmd(control_sock,"PASS ",FtpPass,"230") != 0)
	{
		printf("submit pass word error");
		return 0;
	}

	//设置PASV模式
	if (0 == (portnum = FTP_pasv_mode()))			
	{
		printf("get port fail !");
		return -1;
	}

	//申请数据流socket
	data_sock = socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == data_sock)
	{
		printf("data socket fail ! \r\n");
		return -1;
	}
	printf("data socket ok !\r\n");

	//建立数据连接
	bzero(&s_add,sizeof(struct sockaddr_in));
	s_add.sin_family=AF_INET;
	s_add.sin_addr.s_addr= inet_addr(HostIP);//("127.0.0.1");
	s_add.sin_port=htons(portnum);
	printf("s_addr = %#x ,port : %#x\r\n",s_add.sin_addr.s_addr,s_add.sin_port);
	if(-1 == connect(data_sock,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
	{
	  printf("connect fail !\r\n");
	  return -1;
	}
	printf("connect ok !\r\n");

	//设置数据传输格式
	if (0 != FTP_send_cmd(control_sock,"TYPE I",0,"200"))
	{
		printf("set data format fail !\r\n");
		return -1;
	}

	//get file size
	if (FTP_send_cmd(control_sock,"SIZE ",FileName,"213") != 0)
	{
		printf("get file size fail !\r\n");
		return -1;
	}
	sscanf(buffer,"%d %d",&FileSize,&FileSize);		//返回的第二个数位文件大小
	printf("file size : %d",FileSize);

	//creat the file
	if (NULL == (FPtr = fopen(FileName,"w")))
	{
		printf("Cannot creat this file: %s\n",FileName);
		return -1;
	}	

	//down file
	if (FTP_send_cmd(control_sock,"RETR ",FileName,"150") == 0)
	{
		while(DataSize < FileSize)
		{
			if(-1 == (recbytes = read(data_sock,data_buffer,2048)))
			{
				printf("read data fail !\r\n");
				return -1;
			}
			DataSize += recbytes;
			fwrite(data_buffer,recbytes,1,FPtr);			//wirte data to file
			if (Percent != DataSize*100/FileSize)
			{
				Percent = DataSize*100/FileSize;
				printf("Recv: %d%%\r\n",Percent);
			}
		}
		printf("Recv %d bytes\r\n",DataSize);
		close(data_sock);
		FTP_send_cmd(control_sock,"QUIT",0,"200");
		close(control_sock);
	}

	fclose(FPtr);

	return 0;
}

//*****************************************************************************
//! \Function    : FTP_send_cmd
//! \CreatDate   : 2013-05-09 
//! \Author      : BenPao
//!
//! \Descrip     : set server to pasv mode
//!                
//!                
//!                
//! \Input       :
//! \Output      : 0 - fail ,otherwise return the port
//!
//! \Note        :
//*****************************************************************************
u_short FTP_pasv_mode(void)
{
	u_char *ptr = 0;
	u_char IpPort[6] = {0};									//store the ip and port
	u_short Port = 0;

	if (FTP_send_cmd(control_sock,"PASV",0,"230") == 0)
	{
		printf("set PASV mode fail !");
		return 0;
	}

	if (0 != (ptr = strstr(buffer,"(")))
	{
		sscanf(ptr+1,"%d,%d,%d,%d,%d,%d",&IpPort[0],&IpPort[1],&IpPort[2],&IpPort[3],&IpPort[4],&IpPort[5]);
		Port = IpPort[4];
		Port <<= 8;
		Port |= IpPort[5];
		printf("Port:%d\r\n",Port);
	}

	return Port;
}

//*****************************************************************************
//! \Function    : FTP_send_cmd
//! \CreatDate   : 2013-03-22 星期五 16:39:38
//! \Author      : BenPao
//!
//! \Descrip     : pCMD - pointed to the cmd want to send to FTP server
//!                pPara - pointed to the parameter of cmd
//!                pResp - the response wanted
//!                control_sock   - socket
//! \Input       :
//! \Output      : 0 - success ,
//!
//! \Note        :
//*****************************************************************************
u_char FTP_send_cmd(int fd, u_char *pCMD,u_char *pPara,u_char *pResp)
{
	u_char strSend[100] = {0};
	u_char strTem[100] = {0};
	u_short CntWait = 0;
	int recbytes;

	//send command to server
	strcat((char *)strSend,(const char*)pCMD);
	if (pPara != 0)                                           //该命令带参数
	{
	strcat((char*)strSend,(const char*)pPara);
	}
	strcat((char*)strSend,(const char*)"\r\n");

	if(-1 == write(fd,strSend,sizeof(strSend)))
	{
	printf("write %s fail!\r\n",strSend);
	return 1;
	}
	printf("write %s",strSend);

	//receive the response from server
	recbytes = read(fd,buffer,1024);
	if(-1 == recbytes)
	{
	  printf("read data fail !\r\n");
	  return 3;
	}
	else if (0 == recbytes)
	{
		printf("read 0 byte !\r\n");
	  return 3;
	}
	buffer[recbytes]='\0';
	printf("%s\r\n",buffer);
	if(strstr((const char *)buffer,(const char*)pResp)==0)
	{
		// printf("\r\nserver response error:%s",buffer);
		return 3;
	}

  return 0;
}
分享到: 更多
版权申明:

本站保留所有原创文章的版权,本站地址:奔跑的博客[http://www.elecbench.com]

原创文章转载时请注明出处,并添加文章所在页面的链接:http://www.elecbench.com/linux%e4%b8%8bsocket%e7%bc%96%e7%a8%8b%e4%b9%8b%e5%ae%9e%e7%8e%b0ftp-client/

本站所有 2010年3月4日 以后发表、未标明为“转载”的文章均是本站原创。

发表评论


(设置自己的个性头像)

*

申请属于你的免费顶级域名