您的位置:首页 > 编程语言 > C语言/C++

C++实现FTP参考代码 2011

2012-11-13 11:11 295 查看
#include <sys/types.h>

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

#include <stdarg.h> //to use va_list

#include <string.h>

#include <sys/stat.h>

#include <time.h>

#include <sys/socket.h>

#include <fcntl.h> //file

#include <pwd.h>

#include <grp.h>

#include <dirent.h>
#define ARRAY_LENGTH(arr) (sizeof(arr)/sizeof(arr[0])) //结构体元素个数

#include "ftp_server.h"
int ftp_srv_port =21;

int ftp_quit_flag;

struct ftp_user_struct *ftp_cur_user;

int ftp_pasv_socket = -1;

int ftp_pasv_control_socket = -1;

int ftp_port_control_socket = -1;

char ftp_home_dir[PATH_MAX];

int ftp_cur_child_num;
struct ftp_user_struct *ftp_cur_user;
static int

ftp_create_srv(void) // Create ftp server's listening socket.

{

int listen_socket;

int on = 1;

int nresult;

struct sockaddr_in srvaddr;
if ((listen_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

printf("socket() failed\n");

return listen_socket;

}
nresult = setsockopt(listen_socket, SOL_SOCKET
, SO_REUSEADDR, &on, sizeof(on));

if (nresult < 0)

{

printf("setsockopt() failed\n");

close(listen_socket);

return -1;

}

memset(&srvaddr, 0, sizeof(srvaddr));

srvaddr.sin_family = AF_INET;

srvaddr.sin_port = htons(ftp_srv_port);

srvaddr.sin_addr.s_addr = htonl(INADDR_ANY); //The address is local host
nresult = bind(listen_socket, (struct sockaddr*)&srvaddr,
sizeof(srvaddr)); //to bind the port and address

if (nresult < 0) {

printf("bind() failed \n");

close(listen_socket);

return -1;

}
nresult = listen(listen_socket, FTP_LISTEN_QU_LEN);
//the max queue is 8 by default

if (nresult < 0) {

printf("listen() failed: %s\n", strerror(errno));

close(listen_socket);

return -1;

}
// message

int len = sizeof(srvaddr);

getsockname(listen_socket, (struct sockaddr*)&srvaddr, &len);

printf("Create server listen socket successed: %s:%d\n",
inet_ntoa(srvaddr.sin_addr), ntohs(srvaddr.sin_port));

// end message

return sock;

}

static int mul_client_run(int listenfd)

{

int connfd;

int pid;
while (1) {

printf("Server ready, wait client's connection...%s", "\n");
connfd = accept(listenfd, NULL, NULL);// no need to save the resquset host address information

if (connfd < 0) {

printf("accept() failed: %s\n", strerror(errno));

continue;

}

// message

struct sockaddr_in client_addr;

int len = sizeof(client_addr);

getpeername(connfd, (struct sockaddr*)&client_addr, &len);

printf("accept a conn from %s:%d\n",

inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));

// message

switch(pid=fork()) //为每一个新进来的客户端创建子进程,单独处理

{

case -1:

{

perror("The fork failed!");

}

case 0:

{

close(listenfd);

printf("child");

if (ftp_conn_handler(connfd) != 0)

exit(-1);

exit(0);

}

default:

{

close(connfd);

ftp_cur_child_num++;

printf("client number: %d",ftp_cur_child_num);

continue;

}

}

exit(0);

}
return 0;

}

static int ftp_conn_handler(int connfd) //处理客户端的函数

{

char buf[BUFSIZ];

int buflen;

int err =0;

// Control connection has set up,

if (ftp_send_resp(connfd, 220) != 0)
//给客户端发送命令

{

close(connfd);

printf("Close the ctrl connection OK%s", "\n");

return -1;

}

while (1) //死循环接收客户端发送的消息

{

buflen = ftp_recv_msg(connfd, buf, sizeof(buf));

if (buflen < 0) {

printf("ftp_recv_msg() failed: %s\n", strerror(errno));

err =-1;

break;

}

if (buflen == 0)

break;
buf[buflen] = '\0';

analy_ftp_requestmsg(connfd, buf);
//分析客户端发送的消息内容
if (ftp_quit_flag)

break;

}
close(connfd);

printf("Close the controll connection OK%s", "\n");

return err;

}

static int ftp_send_resp(int fd, int num, ...)

{

int i;

char buf[8];

snprintf(buf, sizeof(buf), "%d", num);

if (strlen(buf) != 3)

return NULL;

char* cp;

for (i = 0; i < ARRAY_LENGTH(ftp_srv_resps_struct); i++)

{

if (strncmp(buf, ftp_srv_resps_struct[i], 3) == 0)
//比较字符串str1和str2的前3个字符

{

cp = ftp_srv_resps_struct[i]; //返回命令号

break;

}

}

va_list ap;

char buf[BUFSIZ];
va_start(ap, num);

vsnprintf(buf, sizeof(buf), cp, ap);

va_end(ap);
printf("Server response code:%s\n", buf);

if (ftp_send_msg(fd, buf, strlen(buf)) != strlen(buf)) {

printf("ftp_send_msg() failed: %s\n", strerror(errno));

return -1;

}
return 0;

}

static int ftp_send_msg(int fd, char *msgbuffer, int len)

{

int nsendnum, nhave_send = 0;

int nsend_left = len;
while (1)

{

nsendnum = write(fd, msgbuffer + nhave_send, nsend_left);

if (nsendnum < 0)

{

if (errno == EINTR)

continue;

return n;

}

if (nsendnum < left)

{

nsend_left -= nsendnum;

nhave_send += nsendnum;

continue;

}

return len;

}

}
static int ftp_recv_msg(int fd, char buf[], int len)

{

int nrecv_num;
while (1)

{

nrecv_num = read(fd, buf, len);

if (nrecv_num < 0) {

continue;

return nrecv_num;

}

return nrecv_num;

}

}

//分析客户端发送的消息内容

static int analy_ftp_requestmsg(int connsockfd, char buf[])

{

char *pstrend = &buf[strlen(buf) - 1];
if (*pstrend == '\n' || *pstrend == '\r') //判断客户端是否执行了回车

{

if (buf && strlen(buf) > 0)

{

for (int i = 0; ftp_cmds[i].cmd_name; i++)

{

if (strcmp(buf, ftp_cmds[i].cmd_name) == 0) //数据判断正确

{

printf("recved a valid ftp cmd:%s\n", buf);

return ftp_cmds[i].cmd_handler(connsockfd, buf);
//接收数据正确,函数指针则执行对应的函数

}

}

return ftp_send_resp(connsockfd, 500, buf);

printf("recved a unsupported ftp cmd:%s\n", buf);

}

}

printf("recved a invalid ftp cmd:%s\n", buf);

return ftp_send_resp(connsockfd, 550);

}
static int ftp_user(int connsockfd, char *cmdbuffer)
//客户端发送命令USER时,服务器执行函数

{

// char *cp = strchr(cmdbuffer, ' '); //查找字符串s中首次出现空字符的位置
if (cmdbuffer)

{

int i;
for (i = 0; i < ARRAY_LENGTH(ftp_users); i++)
//循环查找对应的ftp用户名

if (strcmp(cp + 1, ftp_users[i].user) == 0)

{

printf("user(%s) is found\n", cp + 1);

ftp_cur_user = &ftp_users[i]; //set current user

break;

}
if (!ftp_cur_user)

printf("user(%s) not found\n", cp + 1);

return ftp_send_resp(connsockfd, 331, cp + 1);
//如果用户名正确则发送密码请求

}

return ftp_send_resp(connsockfd, 550);

}
//判断密码确认正确

static int ftp_pass(int ctrlfd, char *cmdbuffer)

{
if (cmdbuffer && ftp_cur_user)

{

printf("papapssss%s\n", cmdbuffer);

if (strlen(ftp_cur_user->pass) != 0 ||

strcmp(cmdbuffer, ftp_cur_user->pass) == 0)

{

printf("Password for %s OK\n", ftp_cur_user->user);

return ftp_send_resp(ctrlfd, 230, ftp_cur_user
->user);//The pass word is correct

}

printf("password for %s ERR\n", ftp_cur_user->user);

}
ftp_cur_user = NULL;

return ftp_send_resp(ctrlfd, 530, "Login failed!");

}
//客户端要求服务器开始socket服务,进入passive模式

static int ftp_pasv(int ctrlfd, char *cmdline)

{

struct sockaddr_in pasvaddr;

int len;

unsigned int ip;

unsigned short port;
FTP_CHECK_LOGIN();
if (ftp_pasv_socket >= 0)

{

close(ftp_pasv_socket);

ftp_pasv_socket = -1;

}
ftp_pasv_socket = socket(AF_INET, SOCK_STREAM, 0);

if (ftp_pasv_socket < 0) {

printf("socket() failed: %s\n", strerror(errno));

return ftp_send_resp(ctrlfd, 550);

}

len = sizeof(pasvaddr);

getsockname(ctrlfd, (struct sockaddr*)&pasvaddr, &len);

pasvaddr.sin_port = 0;
if (bind(ftp_pasv_socket, (struct sockaddr*)&pasvaddr, sizeof(pasvaddr)) < 0) {

printf("bind() failed: %s\n", strerror(errno));

close(ftp_pasv_socket);

ftp_pasv_socket = -1;

return ftp_send_resp(ctrlfd, 550);

}
if (listen(ftp_pasv_socket, FTP_LISTEN_QU_LEN) < 0) {

printf("listen() failed: %s\n", strerror(errno));

close(ftp_pasv_socket);

ftp_pasv_socket = -1;

return ftp_send_resp(ctrlfd, 550);

}

len = sizeof(pasvaddr);

getsockname(ftp_pasv_socket, (struct sockaddr*)&pasvaddr, &len);

ip = ntohl(pasvaddr.sin_addr.s_addr);

port = ntohs(pasvaddr.sin_port);

printf("local bind: %s:%d\n", inet_ntoa(pasvaddr.sin_addr), port);
// write local ip/port into response msg and send to client.

return ftp_send_resp(ctrlfd, 227, (ip>>24)&0xff, (ip>>16)&0xff,

(ip>>8)&0xff, ip&0xff, (port>>8)&0xff, port&0xff);
}
// 给客户设置ip和端口号
static int ftp_port(int ctrlfd, char *cmdline)

{

unsigned int ip;

unsigned short port;

struct sockaddr_in sin;
FTP_CHECK_LOGIN();

char *cp = strchr(cmdline, ' ');

unsigned char buf[6];

cp++;

for ( int i = 0; i < ARRAY_LENGTH(buf); i++)

{

buf[i] = atoi(cp);

cp++;

}

*ip = *(unsigned int*)&buf[0];

*port = *(unsigned short*)&buf[4];
memset(&sin, 0, sizeof(sin));

sin.sin_family = AF_INET;

sin.sin_addr.s_addr = ip;

sin.sin_port = port;

printf("PORT cmd:%s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
if (ftp_port_control_socket >= 0)

{

close(ftp_port_control_socket);

ftp_port_control_socket = -1;

}
ftp_port_control_socket = socket(AF_INET, SOCK_STREAM, 0);

if (connect(ftp_port_control_socket, (struct sockaddr*)&sin, sizeof(sin)) < 0)

{

printf("bind() failed:%s\n", strerror(errno));

if (ftp_port_control_socket >= 0)

{

close(ftp_port_control_socket);

ftp_port_control_socket = -1;

}

return ftp_send_resp(ctrlfd, 550);

}
printf("PORT mode connect OK%s", "\n");

return ftp_send_resp(ctrlfd, 200);

}
static int ftp_stor(int ctrlfd, char *cmdline) //服务端接收文件操作函数

{

char buf[BUFSIZ];
struct stat st;

int fd = -1, n;

int left, off;

int connfd;

char* space = strchr(cmdline, ' ') ;

FTP_CHECK_LOGIN();

if (!space || lstat(space + 1, &st) == 0)

{

printf("STOR cmd err: %s\n", cmdline);

goto err_label;

}

if ((connfd = ftp_get_control_sock()) < 0)
//服务端接受请求并为客户创造单独的socket

{

printf("ftp_get_control_sock() failed%s", "\n");

goto err_label;

}
ftp_send_resp(ctrlfd, 150);

//新建一个可读写文件

if ((fd = open(space + 1, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0)

{

printf("open() failed: %s\n", strerror(errno));

goto err_label;

}
//begin to read data from socket and wirte to disk file

while (1) //死循环接受客户文件信息

{

if ((n = ftp_recv_msg(connfd, buf, sizeof(buf))) < 0)

{

printf("ftp_recv_msg() failed: %s\n", strerror(errno));

return -1;

}
if (n == 0)

break;
left = n;

off = 0;

while (left > 0)

{

int nwrite;
if ((nwrite = write(fd, buf + off, left)) < 0)

{ //循环将接受到的内容写入新建文件

if (errno == EINTR)

continue;

printf("write() failed:%s\n", strerror(errno));

}

off += nwrite;

left -= nwrite;

}

}
printf("STOR(%s) OK\n", space+1);

if (fd >= 0)

close(fd);

ftp_close_all_fd();

sync();

return ftp_send_resp(ctrlfd, 226);

}
static int ftp_get_control_sock(void)

{

int fd;
if (ftp_pasv_socket >= 0)

{

fd = accept(ftp_pasv_socket, NULL, NULL);

if (fd >= 0)

{

close(ftp_pasv_socket);

ftp_pasv_socket = -1;

ftp_pasv_control_socket = fd;

return fd;

}

else

printf("accept() failed:%s\n", strerror(errno));

}

else if (ftp_port_control_socket >= 0)

return ftp_port_control_socket;

return (-1);

}
static int ftp_retr(int ctrlfd, char *cmdline) //发送文件函数

{

char buf[BUFSIZ];

struct stat st;

int fd = -1, n;

int connfd;
FTP_CHECK_LOGIN();
if (!strchr(cmdline, ' ') || lstat(space + 1, &st) < 0)

{

printf("RETR cmd err: %s\n", cmdline);

if (fd >= 0)

close(fd);

ftp_close_all_fd();

return ftp_send_resp(ctrlfd, 550);

}
if ((connfd = ftp_get_control_sock()) < 0) //新建客户端对象

{

printf("ftp_get_control_sock() failed%s", "\n");

if (fd >= 0)

close(fd);

ftp_close_all_fd();

return ftp_send_resp(ctrlfd, 550);

}
ftp_send_resp(ctrlfd, 150);

if ((fd = open(space + 1, O_RDONLY)) < 0) {

printf("open() failed: %s\n", strerror(errno));

if (fd >= 0)

close(fd);

ftp_close_all_fd();

return ftp_send_resp(ctrlfd, 550);

}
while (1) //循环传输文件

{

if ((n = read(fd, buf, sizeof(buf))) < 0) //从文件中读取信息放入buf

{

if (errno == EINTR)

continue;

printf("read() failed: %s\n", strerror(errno));

if (fd >= 0)

close(fd);

ftp_close_all_fd();

return ftp_send_resp(ctrlfd, 550);

}
if (n == 0)

break;

if (ftp_send_msg(connfd, buf, n) != n) //发送buf中的信息到客户

{

printf("ftp_send_msg() failed: %s\n", strerror(errno));

if (fd >= 0)

close(fd);

ftp_close_all_fd();

return ftp_send_resp(ctrlfd, 550);

}

}
printf("RETR(%s) OK\n", space + 1);

if (fd >= 0)

close(fd);

ftp_close_all_fd();

return ftp_send_resp(ctrlfd, 226);
}
static int ftp_close_all_fd(void)

{

if (ftp_pasv_socket >= 0) {

close(ftp_pasv_socket);

ftp_pasv_socket = -1;

}

if (ftp_pasv_control_socket >= 0) {

close(ftp_pasv_control_socket);

ftp_pasv_control_socket = -1;

}

if (ftp_port_control_socket >= 0) {

close(ftp_port_control_socket);

ftp_port_control_socket = -1;

}

return 0;

}

//This function acts as a implementation as 'ls -l' shell command.
static int ftp_list(int ctrlfd, char *cmdline)

{

char buf[BUFSIZ];

int n;

int fd;
FTP_CHECK_LOGIN();
if ((fd = ftp_get_control_sock()) < 0) {

printf("LIST cmd:no available fd%s", "\n");

ftp_close_all_fd();

return ftp_send_resp(ctrlfd, 550);

}
ftp_send_resp(ctrlfd, 150);
// send the 'ls -l' result to client.

// n = ftp_get_list(buf, sizeof(buf));

int temp,n;

system("ls -l>.temp");

temp=open("./.temp", O_RDONLY);

if(temp<0)

{

puts ("OPEN .temp ERROR");

}

else

{

n=read(temp,buf,len);

//printf("hahah%s\n",buf);

}

system("rm -f ./.temp");
if (n >= 0) {

if (ftp_send_msg(fd, buf, n) != n) {

printf("ftp_send_msg() failed: %s\n", strerror(errno));

ftp_close_all_fd();

return ftp_send_resp(ctrlfd, 550);

}

}

else {

printf("ftp_get_list() failed %s", "\n");

ftp_close_all_fd();

return ftp_send_resp(ctrlfd, 550);

}

ftp_close_all_fd();

return ftp_send_resp(ctrlfd, 226);
// data transfer successed and close the data connection

}

char ftp_srv_resps_struct[][256] = { //服务器发送命令消息

"150 Begin transfer" "\r\n", //开始传输

"200 OK" "\r\n",

"213 %d" "\r\n",

"220 MyServer" "\r\n",
//

"221 Goodbye" "\r\n",
//离开

"226 Transfer complete" "\r\n", //传输完成

"227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)" "\r\n", //进入Passive模式

"230 User %s logged in" "\r\n", //用户登录

"250 CWD command successful" "\r\n", //

"257 \"%s\" is current directory" "\r\n", //当前目录

"331 Password required for %s" "\r\n", //密码请求

"500 Unsupport command %s" "\r\n", //不支持的ftp类型

"530 Login %s" "\r\n", //登录服务器

"550 Error" "\r\n"

};

struct ftp_cmd_struct { //客户端命令消息结构体

char *cmd_name;

int (*cmd_handler)(int ctrlfd, char *cmd_line); //函数指针

};
struct ftp_cmd_struct ftp_cmds[] = {

{"USER", ftp_user},

{"PASS", ftp_pass},

{"PWD", ftp_pwd},

{"CWD", ftp_cwd},

{"LIST", ftp_list},

{"TYPE", ftp_type},

{"PORT", ftp_port},

{"PASV", ftp_pasv},

{"RETR", ftp_retr},

{"STOR", ftp_stor},

{"QUIT", ftp_quit},

};
struct ftp_user_struct {

char user[128];

char pass[128];

};
struct ftp_user_struct ftp_users[] = {

{"anonymous", ""},

{"user9", "ftp"},

{"movie9","lslslslslsls"}

};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: