简单写了一个ftp客户端和服务器,贴出来,后续完善
client.c
#include#include #include #include #include #include #include #include #include #define BUFSIZE 1024 #define DATAPORT 8899 #define DEBUG 1 #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0) struct cmd_st { char cmd[BUFSIZE]; char arg[BUFSIZE]; }; typedef struct ftp_cmd_handler { const char *cmd; void (*cmd_handler)(int sockfd, struct cmd_st *command); } ftp_cmd_handler_st; void do_list(int sockfd, struct cmd_st *command); void do_stor(int sockfd, struct cmd_st *command); void do_quit(int sockfd, struct cmd_st *command); void do_cdup(int sockfd, struct cmd_st *command); void do_upld(int sockfd, struct cmd_st *command); ftp_cmd_handler_st cmds_handlers[] = { {"list", do_list}, {"stor", do_stor}, {"quit", do_quit}, {"cdup", do_cdup}, {"upld", do_upld} }; int ftpclient_get_command(char *, int, struct cmd_st *); int command_check_exec(int sockfd, struct cmd_st *command); int read_input(char *,int); void command_trim_crlf(char *); void command_split(const char *, struct cmd_st *, char); int read_reply(); int socket_data_create(int sockfd); int socket_accept(int socket_listen); int socket_create(int port); int socket_control; int main(int argc, char *argv[]) { if(argc < 3) { printf("Usage:argments at least threen"); exit(1); } char buffer[BUFSIZE] = {0}; memset(buffer, 0, BUFSIZE); struct cmd_st command; int retcode; int cmd_num; struct sockaddr_in raddr; socklen_t raddrlen = sizeof(raddr); if((socket_control = socket(AF_INET,SOCK_STREAM,0)) < 0) { perror("socket"); exit(1); } raddr.sin_family = AF_INET; raddr.sin_port = htons(atoi(argv[2])); inet_pton(AF_INET, argv[1], &raddr.sin_addr.s_addr); if(connect(socket_control, (struct sockaddr *)&raddr, raddrlen) < 0) { perror("connect"); exit(1); } printf("ready ro read replyn"); printf("reply from server:%dn", read_reply()); printf("read reply OKn"); while(1) { if(ftpclient_get_command(buffer,BUFSIZE,&command) < 0) { printf("1 : invalid commandn"); continue; } #ifdef DEBUG printf("command is %sn",buffer); printf("cmd is %sn strlen of cmd is %dn",command.cmd,(int)strlen(command.cmd)); printf("arg is %sn strlen of arg is %dn",command.arg,(int)strlen(command.arg)); #endif if(send(socket_control, buffer, (int)strlen(buffer)+1, 0) < 0) { close(socket_control); exit(1); } if((cmd_num = command_check_exec(socket_control, &command)) < 0) { printf("2: invalid commandn"); continue; } // if(retcode == 221) //quit // { // //close all; // } // else if(retcode == 502) // { // //show wrong msg; // } // else{ // // //create socket_date // } } } void do_list(int sockfd, struct cmd_st *command) { read_reply(); printf("enter do_listn"); int num_recvd; int server_response; char buf[BUFSIZE]; int socket_data = socket_data_create(sockfd); //TO DO if(socket_data < 0) { perror("client create socket_data error"); exit(1); } printf("socket_data is %dn", socket_data); memset(buf, 0, BUFSIZE); while((num_recvd = recv(socket_data, buf, BUFSIZE, 0)) > 0) { printf("%s", buf); memset(buf, 0, BUFSIZE); } if(num_recvd < 0) { perror("socket_data:recv"); } if(recv(sockfd, &server_response, sizeof(server_response), 0) < 0) { ERR_EXIT("socket_control:recv response"); } close(socket_data); } void do_stor(int sockfd, struct cmd_st *command) { read_reply(); printf("enter do_storn"); int num_recvd; int server_response; char buf[BUFSIZE]; int reply; int socket_data = socket_data_create(sockfd); //TO DO if(socket_data < 0) { perror("client create socket_data error"); exit(1); } reply = read_reply(); if(reply == 550) { printf("reply is 550 error"); close(socket_data); return; } char data[BUFSIZE]; int recv_size; FILE *fd = fopen(command->arg, "w"); memset(buf, 0, BUFSIZE); while((recv_size = recv(socket_data, data, BUFSIZE, 0)) > 0) { fwrite(data, 1, recv_size, fd); } if(recv_size < 0) { perror("error"); } fclose(fd); printf("stor OK read reply is %dn",read_reply()); close(socket_data); } void do_cdup(int sockfd, struct cmd_st *command) { read_reply(); printf("Enter do_cdupn"); if(read_reply() == 226) { printf("chdir OKn"); } else { printf("chdir errorn"); } } void do_quit(int sockfd, struct cmd_st *command) { printf("quit OKn"); close(sockfd); exit(0); } int socket_data_create(int sockfd) { int socket_listen = socket_create(DATAPORT); int ack = 1; if(send(sockfd, &ack, sizeof(ack), 0) < 0) { perror("send ack"); exit(1); } printf("Enter socket_data_create:send ack OKn"); int socket_data = socket_accept(socket_listen); close(socket_listen); return socket_data; } void do_upld(int sockfd, struct cmd_st *command) { read_reply(); printf("enter do_upldn"); int reply; int socket_data = socket_data_create(sockfd); //TO DO if(socket_data < 0) { perror("client create socket_data error"); exit(1); } FILE *fd = NULL; char data[BUFSIZE]; size_t num_read; memset(data, 0, BUFSIZE); fd = fopen(command->arg, "r"); if(fd == NULL) { perror("fopen"); return; } else { reply = read_reply(); do { num_read = fread(data, 1, BUFSIZE, fd); if(num_read < 0) { printf("error in fread()"); } if(send(socket_data, data, num_read, 0) < 0) { perror("stor:send"); } }while(num_read > 0); fclose(fd); close(socket_data); printf("reply beforen"); read_reply(); printf("reply aftern"); } } int socket_accept(int socket_listen) { int fd; struct sockaddr_in raddr; socklen_t raddrlen = sizeof(raddr); memset(&raddr, 0, sizeof(raddr)); char raddrbuf[BUFSIZE] = {0}; fd = accept(socket_listen, (struct sockaddr *)&raddr, &raddrlen); if(fd < 0) { ERR_EXIT("accept"); } inet_ntop(AF_INET, &raddr.sin_addr.s_addr, raddrbuf, BUFSIZE); printf("message from %s:%dn", raddrbuf , ntohs(raddr.sin_port)); return fd; } int socket_create(int port) { int sd; struct sockaddr_in laddr; socklen_t raddrlen = sizeof(laddr); memset(&laddr,0,sizeof(laddr)); if( (sd = socket(AF_INET,SOCK_STREAM,0)) < 0) { ERR_EXIT("socket"); } int on = 1; if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { close(sd); ERR_EXIT("setsockopt"); } laddr.sin_family = AF_INET; laddr.sin_port = htons(port); inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr.s_addr); if(bind(sd,(struct sockaddr *)&laddr, sizeof(laddr)) < 0) { close(sd); ERR_EXIT("bind"); } if(listen(sd,5) < 0) { close(sd); ERR_EXIT("listen"); } return sd; } int read_reply() { int retcode = 0; int read_num = 0; if((read_num = recv(socket_control, &retcode, sizeof(retcode),0)) < 0) { perror("client:error in reading server message"); printf("socket_control :%dn",socket_control); } return ntohl(retcode); } int ftpclient_get_command(char *buffer,int size,struct cmd_st *command) { memset(buffer, 0, size); memset(command, 0, sizeof(struct cmd_st)); // printf("buffer:%sn",buffer); // printf("command->cmd:%sn",command->cmd); // printf("command->arg:%sn",command->arg); printf("FtpClient> "); fflush(stdout); if(read_input(buffer, size) < 0) { return -1; } command_trim_crlf(buffer); printf("cmd is %sn strlen of cmd is %dn",command->cmd,(int)strlen(command->cmd)); printf("arg is %sn strlen of arg is %dn",command->arg,(int)strlen(command->arg)); command_split(buffer,command, ' '); printf("cmd is %sn strlen of cmd is %dn",command->cmd,(int)strlen(command->cmd)); printf("arg is %sn strlen of arg is %dn",command->arg,(int)strlen(command->arg)); return 0; } int command_check_exec(int sockfd, struct cmd_st *command) { int num_of_cmds_handlers = sizeof(cmds_handlers) / sizeof(cmds_handlers[0]); int i; for(i=0; i cmd) == 0) { printf("command num is %dn",i); cmds_handlers[i].cmd_handler(sockfd, command); return 0; } } return -1; } int read_input(char *buffer,int size) { char *tail = NULL; memset(buffer, 0, size); if(fgets(buffer,size,stdin) != NULL) { tail = strchr(buffer,'n'); if(tail) *tail = ' '; } if(buffer == NULL) { return -1; } return 0; } void command_trim_crlf(char *command) { char *p = &command[strlen(command)-1]; while (*p == 'r' || *p == 'n') *p-- = ' '; } void command_split(const char *cmdline, struct cmd_st *command, char c) { char *p; p = strchr(cmdline,c); if(p == NULL) //only have cmd ,do not have arg { strcpy(command->cmd,cmdline); } else { strncpy(command->cmd,cmdline,p-cmdline); command->cmd[p-cmdline] = ' '; strcpy(command->arg,p+1); printf("arg %dn",(int)strlen(command->arg)); } }
server.c
#include#include #include #include #include #include #include #include #include #include #include #include #define FTP_DATACONN 150 #define FTP_NOOPOK 200 #define FTP_TYPEOK 200 #define FTP_PORTOK 200 #define FTP_EPRTOK 200 #define FTP_UMASKOK 200 #define FTP_CHMODOK 200 #define FTP_EPSVALLOK 200 #define FTP_STRUOK 200 #define FTP_MODEOK 200 #define FTP_PBSZOK 200 #define FTP_PROTOK 200 #define FTP_OPTSOK 200 #define FTP_ALLOOK 202 #define FTP_FEAT 211 #define FTP_STATOK 211 #define FTP_SIZEOK 213 #define FTP_MDTMOK 213 #define FTP_STATFILE_OK 213 #define FTP_SITEHELP 214 #define FTP_HELP 214 #define FTP_SYSTOK 215 #define FTP_GREET 220 #define FTP_GOODBYE 221 #define FTP_ABOR_NOCONN 225 #define FTP_TRANSFEROK 226 #define FTP_ABOROK 226 #define FTP_PASVOK 227 #define FTP_EPSVOK 229 #define FTP_LOGINOK 230 #define FTP_AUTHOK 234 #define FTP_CWDOK 250 #define FTP_RMDIROK 250 #define FTP_DELEOK 250 #define FTP_RENAMEOK 250 #define FTP_PWDOK 257 #define FTP_MKDIROK 257 #define FTP_GIVEPWORD 331 #define FTP_RESTOK 350 #define FTP_RNFROK 350 #define FTP_IDLE_TIMEOUT 421 #define FTP_DATA_TIMEOUT 421 #define FTP_TOO_MANY_USERS 421 #define FTP_IP_LIMIT 421 #define FTP_IP_DENY 421 #define FTP_TLS_FAIL 421 #define FTP_BADSENDCONN 425 #define FTP_BADSENDNET 426 #define FTP_BADSENDFILE 451 #define FTP_BADCMD 500 #define FTP_BADOPTS 501 #define FTP_COMMANDNOTIMPL 502 #define FTP_NEEDUSER 503 #define FTP_NEEDRNFR 503 #define FTP_BADPBSZ 503 #define FTP_BADPROT 503 #define FTP_BADSTRU 504 #define FTP_BADMODE 504 #define FTP_BADAUTH 504 #define FTP_NOSUCHPROT 504 #define FTP_NEEDENCRYPT 522 #define FTP_EPSVBAD 522 #define FTP_DATATLSBAD 522 #define FTP_LOGINERR 530 #define FTP_NOHANDLEPROT 536 #define FTP_FILEFAIL 550 #define FTP_NOPERM 550 #define FTP_UPLOADFAIL 553 #define BUFSIZE 1024 #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0) #define DATAPORT 8899 struct cmd_st { char cmd[BUFSIZE]; char arg[BUFSIZE]; }; typedef struct ftp_cmd_handler { const char *cmd; void (*cmd_handler)(int sockfd, struct cmd_st *command); } ftp_cmd_handler_st; void do_list(int sockfd, struct cmd_st *command); void do_stor(int sockfd, struct cmd_st *command); void do_quit(int sockfd, struct cmd_st *command); void do_cdup(int sockfd, struct cmd_st *command); void do_upld(int sockfd, struct cmd_st *command); ftp_cmd_handler_st cmds_handlers[] = { {"list", do_list}, {"stor", do_stor}, {"quit", do_quit}, {"cdup", do_cdup}, {"upld", do_upld} }; int socket_create(int); int socket_accept(int); int send_response(int, int); ssize_t readn(int sd, void * buf, size_t count); int ftpserver_get_command(int fd, char *buffer,int size,struct cmd_st *command); int handle_child(int socket_control); void command_split(const char *cmdline, struct cmd_st *command, char c); void command_trim_crlf(char *command); void handle_sigchld(int sig); int handle_child(int socket_control); int command_check(int sockfd, struct cmd_st *command); size_t recv_data(int fd,char *buffer,int size); ssize_t writen(int fd, const void *buf, size_t count); int socket_data_create(int socket_control); int socket_data_connect(int port, char *addr_buf); int main(int argc, char *argv[]) { if(argc < 2) { printf("Usage:arguments request at least two"); exit(1); } signal(SIGCHLD, handle_sigchld); //TO DO handle_sigchld int socket_listen, socket_control, port; pid_t pid; port = atoi(argv[1]); socket_listen = socket_create(port); if(socket_listen < 0) { ERR_EXIT("socket create error"); } while(1) { socket_control = socket_accept(socket_listen); if(socket_control < 0) { ERR_EXIT("accept"); } if(send_response(socket_control,FTP_GREET) < 0) { printf("send_response errorn"); } printf("send_response OKn"); if((pid = fork()) < 0) { ERR_EXIT("fork"); } if(pid == 0) //child { close(socket_listen); signal(SIGCHLD, SIG_IGN); printf("Enter pid==0n"); handle_child(socket_control); //TO DOi close(socket_control); exit(0); } else //parent { close(socket_control); } } close(socket_control); close(socket_listen); exit(0); } void handle_sigchld(int sig) { pid_t pid; while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { } } void do_list(int sockfd, struct cmd_st *command) { send_response(sockfd,226); printf("Enter do_listn"); int socket_data; if((socket_data = socket_data_create(sockfd)) < 0) { ERR_EXIT("do_list:socket_data_connect"); } printf("socket_data is %dn",socket_data); DIR *dir = opendir("."); if(dir == NULL) { ERR_EXIT("opendir"); } char buf[BUFSIZE]; memset(buf, 0, BUFSIZE); struct dirent *dt; while((dt = readdir(dir)) != NULL) { if(dt->d_name[0] == '.') continue; sprintf(buf, "%srn", dt->d_name); printf("buf:%sn",buf); writen(socket_data, buf, strlen(buf)); memset(buf, 0, BUFSIZE); } closedir(dir); close(socket_data); socket_data = -1; send_response(sockfd, FTP_TRANSFEROK); } void do_stor(int sockfd, struct cmd_st *command) { send_response(sockfd,226); printf("Enter do_storn"); int socket_data; if((socket_data = socket_data_create(sockfd)) < 0) { ERR_EXIT("do_stor:socket_data_connect"); } printf("socket_data is %dn",socket_data); FILE *fd = NULL; char data[BUFSIZE]; size_t num_read; memset(data, 0, BUFSIZE); fd = fopen(command->arg, "r"); if(fd == NULL) { send_response(sockfd,550); } else { send_response(sockfd, 150); do { num_read = fread(data, 1, BUFSIZE, fd); if(num_read < 0) { printf("error in fread()"); } printf("data %sn",data); if(send(socket_data, data, num_read, 0) < 0) { perror("stor:send"); } }while(num_read > 0); send_response(sockfd,226); fclose(fd); } close(socket_data); } void do_cdup(int sockfd, struct cmd_st *command) { send_response(sockfd, 226); printf("Enter do_cdupn"); if(chdir("..") < 0) { send_response(sockfd, 550); } else { send_response(sockfd, 226); } } void do_quit(int sockfd, struct cmd_st *command) { printf("quit OKn"); close(sockfd); exit(0); } void do_upld(int sockfd, struct cmd_st *command) { send_response(sockfd,226); printf("Enter do_upldn"); int socket_data; if((socket_data = socket_data_create(sockfd)) < 0) { ERR_EXIT("do_upld:socket_data_connect"); } send_response(sockfd, 226); char data[BUFSIZE]; int recv_size; FILE *fd = fopen(command->arg, "w"); memset(data, 0, BUFSIZE); while((recv_size = recv(socket_data, data, BUFSIZE, 0)) > 0) { fwrite(data, 1, recv_size, fd); printf("datas are :%sn", data); } if(recv_size < 0) { perror("error"); send_response(sockfd, 550); } printf("begin to fclosen"); fclose(fd); printf("send beforen"); send_response(sockfd, 226); printf("send aftern"); close(socket_data); } ssize_t writen(int fd, const void *buf, size_t count) { size_t nleft = count; ssize_t nwritten; char *bufp = (char*)buf; while (nleft > 0) { if ((nwritten = write(fd, bufp, nleft)) < 0) { if (errno == EINTR) continue; return -1; } else if (nwritten == 0) continue; bufp += nwritten; nleft -= nwritten; } return count; } int socket_data_create(int socket_control) { int wait = 1; printf("Enter socket_data_createn"); if(recv(socket_control, &wait, sizeof(wait), 0) < 0) { perror("socket_data_connect:recv"); return -1; } printf("Enter socket_data_create:recv wait OKn"); int socket_data; char addr_buf[BUFSIZE]; struct sockaddr_in client_addr; memset(addr_buf, 0, BUFSIZE); socklen_t client_addr_len = sizeof(client_addr); getpeername(socket_control, (struct sockaddr *)&client_addr, &client_addr_len); inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, addr_buf, BUFSIZE); if((socket_data = socket_data_connect(DATAPORT,addr_buf)) < 0) { return -1; } printf("get socket_datan"); return socket_data; } int socket_data_connect(int port, char *addr_buf) { int sockfd; struct sockaddr_in client_addr; if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket_data_connect:socket"); return -1; } printf("Enter socket_data_connectn"); memset(&client_addr, 0, sizeof(client_addr)); client_addr.sin_family = AF_INET; client_addr.sin_port = htons(port); inet_pton(AF_INET, addr_buf, &client_addr.sin_addr.s_addr); if(connect(sockfd,(struct sockaddr *)&client_addr, sizeof(client_addr)) < 0) { perror("socket_data_connect:connect"); return -1; } return sockfd; } int handle_child(int socket_control) { while(1) { char buffer[BUFSIZE]; struct cmd_st command; //wait for a command if(ftpserver_get_command(socket_control, buffer, BUFSIZE, &command) < 0) { break; } if(command_check(socket_control, &command) < 0) { //return -1; } } close(socket_control); exit(0); } int ftpserver_get_command(int fd, char *buffer,int size,struct cmd_st *command) { memset(buffer, 0, size); memset(command, 0, sizeof(struct cmd_st)); if(recv_data(fd, buffer, size) < 0) { //TO DO } printf("recvbuf is %sn",buffer); command_trim_crlf(buffer); command_split(buffer,command, ' '); printf("recvbuf is %sn cmd is %sn arg is %sn",buffer, command->cmd, command->arg); return 0; } size_t recv_data(int fd,char *buffer,int size) { size_t num_bytes; if((num_bytes = recv(fd, buffer, size, 0)) == -1) { perror("recv_data:recv"); return -1; } printf("recv :%sn",buffer); return num_bytes; } ssize_t readn(int fd, void * buf, size_t count) { size_t nleft = count; ssize_t nread; char *bufp = (char*)buf; while (nleft > 0) { if ((nread = read(fd, bufp, nleft)) < 0) { if (errno == EINTR) continue; return -1; } else if (nread == 0) return count - nleft; printf("nread is %ldn", nread); bufp += nread; nleft -= nread; } return count; } int command_check(int sockfd, struct cmd_st *command) { int num_of_cmds_handlers = sizeof(cmds_handlers) / sizeof(cmds_handlers[0]); int i; for(i=0; i cmd) == 0) { printf("cmds[%d] is runningn",i); cmds_handlers[i].cmd_handler(sockfd, command); } } return -1; } void command_trim_crlf(char *command) { char *p = &command[strlen(command)-1]; while (*p == 'r' || *p == 'n') *p-- = ' '; } void command_split(const char *cmdline, struct cmd_st *command, char c) { char *p; p = strchr(cmdline,c); if(p == NULL) //only have cmd ,do not have arg { strcpy(command->cmd,cmdline); } else { strncpy(command->cmd,cmdline,p-cmdline); command->cmd[p-cmdline] = ' '; strcpy(command->arg,p+1); printf("arg %dn",(int)strlen(command->arg)); } } int send_response(int socket_control, int retcode) { int temp = htonl(retcode); int send_num = 0; if((send_num = send(socket_control, &temp, sizeof(temp), 0)) < 0) { perror("server:error in sending message to client"); return -1; } printf("send num %dn",send_num); return 0; } int socket_accept(int socket_listen) { int socket_control; struct sockaddr_in raddr; socklen_t raddrlen = sizeof(raddr); memset(&raddr, 0, sizeof(raddr)); char raddrbuf[BUFSIZE] = {0}; socket_control = accept(socket_listen, (struct sockaddr *)&raddr, &raddrlen); if(socket_control < 0) { ERR_EXIT("accept"); } inet_ntop(AF_INET, &raddr.sin_addr.s_addr, raddrbuf, BUFSIZE); printf("message from %s:%dn", raddrbuf , ntohs(raddr.sin_port)); return socket_control; } int socket_create(int port) { int sd; struct sockaddr_in laddr; socklen_t raddrlen = sizeof(laddr); memset(&laddr,0,sizeof(laddr)); if( (sd = socket(AF_INET,SOCK_STREAM,0)) < 0) { ERR_EXIT("socket"); } int on = 1; if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { close(sd); ERR_EXIT("setsockopt"); } laddr.sin_family = AF_INET; laddr.sin_port = htons(port); inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr.s_addr); if(bind(sd,(struct sockaddr *)&laddr, sizeof(laddr)) < 0) { close(sd); ERR_EXIT("bind"); } if(listen(sd,5) < 0) { close(sd); ERR_EXIT("listen"); } return sd; }



