ftp客户端自己搭建,已经测试在linux和windos下面的ftpsvr可以连接成功和传输图像,
出现windos上次图片失败的问题, windos下文件名称不能包含
“?”、“、”、“╲”、“/”、“*”、““”、“”“、“<”、“>”、“|”。:
(需要源码和测试信息联系QQ:123011785)
经过修改测试相对稳定,下面附加代码信息
ftp.h源码:
#ifndef __VSS_FTP_CLIENT_H__
#define __VSS_FTP_CLIENT_H__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define bb_perror_msg(x) printf(x)
#define bb_msg_read_error "Error: bb_msg_read_error"
#define bb_msg_write_error "Error: bb_msg_write_error"
#define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
#define bb_perror_msg_and_die printf
#define bb_error_msg_and_die printf
#define bb_perror_nomsg_and_die() assert(0);
//#define TRACE() printf("%s %d\n", __FUNCTION__, __LINE__);
#define OFF_FMT "l"
typedef struct len_and_sockaddr {
socklen_t len;
union {
struct sockaddr sa;
struct sockaddr_in sin;
};
} len_and_sockaddr;
typedef struct ftp_host_info_s {
const char *user;
const char *password;
struct len_and_sockaddr *lsa;
} ftp_host_info_t;
#ifdef __cplusplus
extern "C"
{
#endif
int xatou(char *buf);
int xatoul_range(char *buf, int low, int top);
len_and_sockaddr *xhost2sockaddr(const char *ip_addr, int port);
char* sockaddr2str(const struct sockaddr *sa, int flags);
char* xmalloc_sockaddr2dotted(const struct sockaddr *sa);
int xopen3(const char *pathname, int flags, int mode);
int xopen(const char *pathname, int flags);
void safe_fclose(FILE *control_stream);
ssize_t safe_read(int fd, void *buf, size_t count);
ssize_t safe_write(int fd, const void *buf, size_t count);
size_t full_write(int fd, const void *buf, size_t len);
off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size);
off_t bb_copyfd_eof(int fd1, int fd2);
void ftp_die(const char *msg, const char *remote);
int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf);
void set_nport(len_and_sockaddr *lsa, unsigned port);
int xconnect_ftpdata(ftp_host_info_t *server, char *buf);
void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen);
int xsocket(int domain, int type, int protocol);
int xclose(int s);
int xconnect_stream(const len_and_sockaddr *lsa);
FILE *ftp_login(ftp_host_info_t *server);
int ftp_mkdir(FILE *control_stream, const char *FoldName);
int ftp_cd(FILE *control_stream, const char *FoldName);
int ftp_send(ftp_host_info_t *server, FILE *control_stream,
const char *server_path, char *local_path);
int ftp_quit(FILE *control_stream);
//int main(void);
#ifdef __cplusplus
}
#endif
#endif
ftp.c源码如下:
#include "ftpclient.h"
#if 0
enum {
LSA_SIZEOF_SA = sizeof(
union {
struct sockaddr sa;
struct sockaddr_in sin;
}
)
};
#endif
typedef struct ftpmissions{
int currmission_id;
int len_missionlist;
}ftpmissions_t;
typedef struct ftpbackupmission_info{
int currfilelist_id;
int len_filelist;
}ftpbackupmission_info_t;
int xatou(char *buf)
{
char c;
int i;
int j = 0;
int retval = 0;
char mod[3] = {1, 10, 100};
int len = strlen(buf);
if ( (!len)||(len > 3) )
{
return -1;
}
for (i = len - 1; i >= 0; i--)
{
c = buf[i];
retval += atoi(&c)*mod[j++];
}
return retval;
}
int xatoul_range(char *buf, int low, int top)
{
int retval = xatou(buf);
if (retval < low)
{
retval = low;
}
if (retval > top)
{
retval = top;
}
// printf("buf = %s\n", buf);
// printf("###retval = %d\n", retval);
return retval;
}
len_and_sockaddr *xhost2sockaddr(const char *ip_addr, int port)
{
int rc;
len_and_sockaddr *r = NULL;
struct addrinfo *result = NULL;
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
hint.ai_family = AF_INET;
hint.ai_socktype = SOCK_STREAM;
rc = getaddrinfo(ip_addr, NULL, &hint, &result);
if (rc||!result)
{
free(r);
r = NULL;
return r;
}
r = (len_and_sockaddr *)malloc(4 + result->ai_addrlen);
if (r == NULL)
{
return NULL;
}
r->len = result->ai_addrlen;
memcpy(&r->sa, result->ai_addr, result->ai_addrlen);
r->sin.sin_port = htons(port);
freeaddrinfo(result);
return r;
}
/******************************************************************/
#define IGNORE_PORT NI_NUMERICSERV
char* sockaddr2str(const struct sockaddr *sa, int flags)
{
char host[128];
char serv[16];
int rc;
socklen_t salen;
//salen = LSA_SIZEOF_SA;
salen = sizeof(sockaddr);
rc = getnameinfo(sa, salen,
host, sizeof(host),
/* can do ((flags & IGNORE_PORT) ? NULL : serv) but why bother? */
serv, sizeof(serv),
/* do not resolve port# into service _name_ */
flags | NI_NUMERICSERV
);
if (rc)
return NULL;
if (flags & IGNORE_PORT)
return strdup(host);
/* For now we don't support anything else, so it has to be INET */
/*if (sa->sa_family == AF_INET)*/
char *retmsg = (char *)malloc(2048);
memset(retmsg, 0, 2048);
sprintf(retmsg, "%s:%s", host, serv);
return retmsg;
/*return xstrdup(host);*/
}
char* xmalloc_sockaddr2dotted(const struct sockaddr *sa)
{
return sockaddr2str(sa, NI_NUMERICHOST);
}
int xopen3(const char *pathname, int flags, int mode)
{
int ret;
ret = open(pathname, flags, mode);
if (ret < 0) {
bb_perror_msg_and_die("can't open '%s'", pathname);
}
return ret;
}
int xopen(const char *pathname, int flags)
{
return xopen3(pathname, flags, 0666);
}
void safe_fclose(FILE *control_stream)
{
if (control_stream != NULL)
{
printf("+++++++++close ftp control_stream!!!!\n\n");
fclose(control_stream);
control_stream = NULL;
}
}
ssize_t safe_read(int fd, void *buf, size_t count)
{
ssize_t n;
do {
n = read(fd, buf, count);
} while (n < 0 && errno == EINTR);
return n;
}
ssize_t safe_write(int fd, const void *buf, size_t count)
{
ssize_t n;
do {
n = write(fd, buf, count);
} while (n < 0 && errno == EINTR);
return n;
}
size_t full_write(int fd, const void *buf, size_t len)
{
ssize_t cc;
ssize_t total;
total = 0;
while (len) {
cc = safe_write(fd, buf, len);
if (cc < 0)
return cc; /* write() returns -1 on failure. */
total += cc;
buf = ((const char *)buf) + cc;
len -= cc;
}
return total;
}
off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
{
int status = -1;
off_t total = 0;
char buffer[BUFSIZ];
if (src_fd < 0)
goto out;
if (!size) {
size = BUFSIZ;
status = 1; /* copy until eof */
}
while (1) {
ssize_t rd;
rd = safe_read(src_fd, buffer, size > BUFSIZ ? BUFSIZ : size);
if (!rd) { /* eof - all done */
status = 0;
break;
}
if (rd < 0) {
bb_perror_msg(bb_msg_read_error);
break;
}
/* dst_fd == -1 is a fake, else... */
if (dst_fd >= 0) {
ssize_t wr = full_write(dst_fd, buffer, rd);
if (wr < rd) {
bb_perror_msg(bb_msg_write_error);
break;
}
}
total += rd;
if (status < 0) { /* if we aren't copying till EOF... */
size -= rd;
if (!size) {
/* 'size' bytes copied - all done */
status = 0;
break;
}
}
}
out:
return status ? -1 : total;
}
off_t bb_copyfd_eof(int fd1, int fd2)
{
return bb_full_fd_action(fd1, fd2, 0);
}
/******************************************************************/
void ftp_die(const char *msg, const char *remote)
{
/* Guard against garbage from remote server */
const char *cp = remote;
while (*cp >= ' ' && *cp < '\x7f') cp++;
bb_error_msg_and_die("unexpected server response%s%s: %.*s\n",
msg ? " to " : "", msg ? msg : "",
(int)(cp - remote), remote);
// assert(0);
}
int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf)
{
unsigned n;
if (s1) {
if (s2) {
fprintf(stream, "%s %s\r\n", s1, s2);
} else {
fprintf(stream, "%s\r\n", s1);
}
}
do {
char *buf_ptr;
if (fgets(buf, 510, stream) == NULL) {
bb_perror_msg_and_die("fgets");
return -1;
}
buf_ptr = strstr(buf, "\r\n");
if (buf_ptr) {
*buf_ptr = '\0';
}
} while (!isdigit(buf[0]) || buf[3] != ' ');
buf[3] = '\0';
n = xatou(buf);
buf[3] = ' ';
return n;
}
void set_nport(len_and_sockaddr *lsa, unsigned port)
{
if (lsa->sa.sa_family == AF_INET) {
lsa->sin.sin_port = port;
return;
}
/* What? UNIX socket? IPX?? :) */
}
int xconnect_ftpdata(ftp_host_info_t *server, char *buf)
{
char *buf_ptr;
unsigned short port_num;
//printf("buf = %s\n", buf);
/* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage]
* Server's IP is N1.N2.N3.N4 (we ignore it)
* Server's port for data connection is P1*256+P2 */
buf_ptr = strrchr(buf, ')');
if (buf_ptr) *buf_ptr = '\0';
buf_ptr = strrchr(buf, ',');
*buf_ptr = '\0';
port_num = xatoul_range(buf_ptr + 1, 0, 255);
buf_ptr = strrchr(buf, ',');
*buf_ptr = '\0';
port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256;
//printf("#### port_num = %d\n", port_num);
set_nport(server->lsa, htons(port_num));
return xconnect_stream(server->lsa);
}
void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
{
if (connect(s, s_addr, addrlen) < 0) {
if (s_addr->sa_family == AF_INET)
bb_perror_msg_and_die("%s (%s)\n",
"cannot connect to remote host",
inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr));
bb_perror_msg_and_die("cannot connect to remote host\n");
// assert(0);
}
}
// Die with an error message if we can't open a new socket.
int xsocket(int domain, int type, int protocol)
{
int r = socket(domain, type, protocol);
if (r < 0) {
/* Hijack vaguely related config option */
#if ENABLE_VERBOSE_RESOLUTION_ERRORS
const char *s = "INET";
if (domain == AF_PACKET) s = "PACKET";
if (domain == AF_NETLINK) s = "NETLINK";
USE_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";)
bb_perror_msg_and_die("socket(AF_%s)", s);
#else
bb_perror_msg_and_die("socket");
#endif
}
return r;
}
int xclose(int s)
{
if (s > 0)
{
close(s);
s = -1;
}
}
int xconnect_stream(const len_and_sockaddr *lsa)
{
int fd = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0);
xconnect(fd, &lsa->sa, lsa->len);
return fd;
}
FILE *ftp_login(ftp_host_info_t *server)
{
FILE *control_stream;
char buf[512];
int login_fd;
/* Connect to the command socket */
login_fd = xconnect_stream(server->lsa);
if(login_fd == -1)
return NULL;
control_stream = fdopen(login_fd, "r+");
if (control_stream == NULL) {
xclose(login_fd);
/* fdopen failed - extremely unlikely */
bb_perror_nomsg_and_die();
return NULL;
}
if (ftpcmd(NULL, NULL, control_stream, buf) != 220) {
ftp_die(NULL, buf);
safe_fclose(control_stream);
return NULL;
}
/* Login to the server */
switch (ftpcmd("USER", server->user, control_stream, buf)) {
case 230:
break;
case 331:
if (ftpcmd("PASS", server->password, control_stream, buf) != 230) {
ftp_die("PASS", buf);
safe_fclose(control_stream);
return NULL;
}
break;
default:
{
ftp_die("USER", buf);
safe_fclose(control_stream);
return NULL;
}
}
if(ftpcmd("TYPE I", NULL, control_stream, buf) == -1)
{
safe_fclose(control_stream);
return NULL;
}
return control_stream;
}
int ftp_mkdir(FILE *control_stream, const char *FoldName)
{
if (strlen(FoldName) <= 0)
{
return -1;
}
char buf[512];
int response = ftpcmd("MKD", FoldName, control_stream, buf);
if(response != 257)
{
//printf("MKD1111111111111111111111:%d\n", response);
ftp_die("MKD", buf);
return -1;
}
//printf("MKD2222222222222222222:%d\n", response);
return 0;
}
int ftp_cd(FILE *control_stream, const char *FoldName)
{
if (strlen(FoldName) <= 0)
{
return -1;
}
char buf[512];
int response = ftpcmd("CWD", FoldName, control_stream, buf);
if(response != 250)
{
//printf("CWD1111111111111111111111response:%d\n", response);
ftp_die("CWD", buf);
return -1;
}
//printf("CWD2222222222222222222response:%d\n", response);
return 0;
}
int ftp_send(ftp_host_info_t *server, FILE *control_stream,
const char *server_path, char *local_path)
{
struct stat sbuf;
char buf[512];
int fd_data;
int fd_local;
int response;
/* Connect to the data socket */
if (ftpcmd("PASV", NULL, control_stream, buf) != 227) {
ftp_die("PASV", buf);
return -1;
}
fd_data = xconnect_ftpdata(server, buf);
if(fd_data == -1)
return -1;
/* get the local file */
fd_local = STDIN_FILENO;
if (NOT_LONE_DASH(local_path)) {
fd_local = xopen(local_path, O_RDONLY);
while(fd_local == -1)
{
xclose(fd_local);
sleep(1);
fd_local = xopen(local_path, O_RDONLY);
}
fstat(fd_local, &sbuf);
sprintf(buf, "ALLO %"OFF_FMT"u", sbuf.st_size);
response = ftpcmd(buf, NULL, control_stream, buf);
switch (response) {
case 200:
case 202:
break;
default:
{
xclose(fd_data);
xclose(fd_local);
ftp_die("ALLO", buf);
return -1;
}
}
}
response = ftpcmd("STOR", server_path, control_stream, buf);
switch (response) {
case 125:
case 150:
break;
default:
{
xclose(fd_data);
xclose(fd_local);
ftp_die("STOR", buf);
return -1;
}
}
/* transfer the file */
ftpmissions_t missionlist={0,0};
ftpbackupmission_info_t filelist={0,0};
do{
do{
if (bb_copyfd_eof(fd_local, fd_data) == -1) {
/* close it all down */
xclose(fd_data);
xclose(fd_local);
return -1;
//exit(EXIT_FAILURE);
}
}while(filelist.currfilelist_id++<=filelist.len_filelist);
}while (missionlist.currmission_id++<=missionlist.len_missionlist);
/* close it all down */
close(fd_data);
close(fd_local);
if (ftpcmd(NULL, NULL, control_stream, buf) != 226) {
ftp_die("close", buf);
return -1;
}
return EXIT_SUCCESS;
}
int ftp_quit(FILE *control_stream)
{
if (control_stream == NULL)
{
return -1;
}
char buf[512];
ftpcmd("QUIT", NULL, control_stream, buf);
safe_fclose(control_stream);
return 0;
}
#if 1
int main(void)
{
//const char *port = "ftp";
FILE *control_stream;
ftp_host_info_t *server;
char local_path[128];
char server_path[128];
server = malloc(sizeof(*server));
if (server == NULL)
{
return -1;
}
server->user = "ftpsvr";
server->password = "123456";
server->lsa = xhost2sockaddr("192.168.1.8", 21);
printf("Connecting to %s (%s)\n", "192.168.1.8",
xmalloc_sockaddr2dotted(&server->lsa->sa));
control_stream = ftp_login(server);
int iret = ftp_cd(control_stream, "screenshort10");
if (iret < 0)
{
ftp_mkdir(control_stream, "screenshort10");
ftp_cd(control_stream, "screenshort10");
}
while(1)
{
sprintf(local_path, "%s", "100421133604-000-3-1.jpg");
sprintf(server_path, "%s", "100421133604-000-3-1.jpg");
if(ftp_send(server, control_stream, server_path, local_path)==-1)
{
fclose(control_stream);
control_stream = NULL;
printf("\nConnecting to %s (%s)\n", "192.168.1.8",
xmalloc_sockaddr2dotted(&server->lsa->sa));
while(control_stream == NULL)
{
server->user = "ftpsvr";
server->password = "123456";
server->lsa = xhost2sockaddr("192.168.1.8", 21);
control_stream = ftp_login(server);
}
}
else
{
//fprintf(stdout,"%s upload success\n",local_path);
}
ftp_quit(control_stream);
break;
}
return 0;
}
#endif