代码语言
.
CSharp
.
JS
Java
Asp.Net
C
MSSQL
PHP
Css
PLSQL
Python
Shell
EBS
ASP
Perl
ObjC
VB.Net
VBS
MYSQL
GO
Delphi
AS
DB2
Domino
Rails
ActionScript
Scala
代码分类
文件
系统
字符串
数据库
网络相关
图形/GUI
多媒体
算法
游戏
Jquery
Extjs
Android
HTML5
菜单
网页交互
WinForm
控件
企业应用
安全与加密
脚本/批处理
开放平台
其它
【
C
】
linux下的简单的ftp实现
作者:
匡峰
/ 发布于
2013/6/4
/
794
支持功能:LIST,RETR,STOR,PORT
#include "ftp_server.h" #include <sys/select.h> #include <sys/types.h> #include <sys/sem.h> #include <sys/ipc.h> #include <pthread.h> static int servfd; static int connlen = 0; static struct serv_cntl_conn *cntl_head = NULL; static int dataquene_sem; in_addr_t localaddr; in_port_t localcntlport; in_port_t localdataport; char homedir[PATH_MAX+1]; static char cntlsendbuf[LINELEN+1]; struct serv_cntl_conn *accept_new_client(int servfd); int do_server_cmd_port(struct serv_cntl_conn *cntl, char *params); void do_server_cmd_transfer(struct serv_data_conn *dconnp); static void transfer_over(struct serv_cntl_conn *cntl) { struct serv_data_conn *dconnp = cntl->dataconn; printf("close data sock: %d\n", dconnp->sockfd); /* 先shutdown是为了让客户端受到连接关闭的通知 */ shutdown(dconnp->sockfd, SHUT_RDWR); close(dconnp->sockfd); cntl->status = CS_WAIT_CMD; dconnp->sockfd = -1; dconnp->pid = -1; } void sig_child(int sig) { pid_t pid = wait(NULL); struct serv_cntl_conn *cntl; for (cntl = cntl_head; cntl; cntl = cntl->next) { struct serv_data_conn *dconnp = cntl->dataconn; if (dconnp && dconnp->pid == pid) { transfer_over(cntl); break; } } if (signal(SIGCHLD, sig_child) == SIG_ERR) { fprintf(stderr, "signal error\n"); } printf("sig child handled. pid=%d\n", pid); } /* init socket ,bind, listen */ static void init_server() { struct addrinfo hints; struct addrinfo *result, *rp; int s, val; char hostname[HOST_NAME_MAX+1]; gethostname(hostname, HOST_NAME_MAX+1); localdataport = htons(SERVER_DATA_PORT); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; s = getaddrinfo(hostname, "ftp", &hints, &result); if(s != 0) { fprintf(stderr, "getaddinfo: %s\n", gai_strerror(s)); exit(EXIT_FAILURE); } for (rp = result; rp != NULL; rp = rp->ai_next) { servfd = initserver(SOCK_STREAM, rp->ai_addr, rp->ai_addrlen, MAX_CONN); if (servfd >= 0){ char addr[INET_ADDRSTRLEN]; struct sockaddr_in * sa_in = (struct sockaddr_in*)rp->ai_addr; in_addr_t in_addr = sa_in->sin_addr.s_addr; inet_ntop(AF_INET, &in_addr, addr, INET_ADDRSTRLEN); fprintf(stdout, "bind on address %s:%u\n", addr, ntohs(sa_in->sin_port)); localaddr = in_addr; localcntlport = sa_in->sin_port; break; } } if (rp == NULL) { fprintf(stderr, "Counld not bind\n"); exit(EXIT_FAILURE); } freeaddrinfo(result); } static void reset_cntl(struct serv_cntl_conn *cntl) { if (cntl == NULL) return; cntl->lineused = 0; cntl->status = CS_WAIT_CMD; } int checkpasswd(char *user, char *passwd) { //TODO: check password return 0; } static int handle_line_request(struct serv_cntl_conn *cntl, char *linerecvd) { struct serv_data_conn *dconnp; int sockfd, n, bufsize, retval; char *params; enum FTP_CMD cmd; struct sembuf sems[] = {{0,1,0}}; if (!cntl || !linerecvd) goto errout; puts("handle_line_request"); retval = pharsecmdline(linerecvd, &cmd, ¶ms); if (retval < 0) { fprintf(stderr, "wrong command: %s\n", linerecvd); goto errout; } fprintf(stdout, "line left --> [%d] %s\n", cntl->lineused, cntl->line); cntl->lastcmd = cmd; if (cntl->lastparams) free(cntl->lastparams); cntl->lastparams = params; switch(cmd) { case CMD_ABOR: break; case CMD_LIST: goto trans; case CMD_PASS: if (cntl->user) { if (checkpasswd(cntl->user, params) == 0) { snprintf(cntlsendbuf, LINELEN, "230 User logged in, proceed.\n"); cntl->logon = 1; } else snprintf(cntlsendbuf, LINELEN, "530 Not logged in.\n"); } else { snprintf(cntlsendbuf, LINELEN, "332 Need account for login.\n"); } write(cntl->sockfd,cntlsendbuf,strlen(cntlsendbuf)); puts(cntlsendbuf); break; case CMD_PORT: if (cntl->status == CS_WAIT_CMD) { if (do_server_cmd_port(cntl, params) == 0) { /* ready for transfer, send response for PORT command */ snprintf(cntlsendbuf, LINELEN, "225 Data connection open; no transfer in progress.\n"); write(cntl->sockfd,cntlsendbuf,strlen(cntlsendbuf)); puts(cntlsendbuf); return 0; } else { goto errout; } } else { printf("receive PORT while status not CS_WAIT_CMD.\n"); goto errout; } break; case CMD_QUIT: break; case CMD_RETR: goto trans; case CMD_STOR: goto trans; case CMD_SYST: break; case CMD_TYPE: break; case CMD_USER: if (!params) break; if (cntl->user) free(cntl->user); cntl->user = strdup(params); cntl->logon = 0; snprintf(cntlsendbuf, LINELEN, "331 User name okay, need password.\n"); write(cntl->sockfd,cntlsendbuf,strlen(cntlsendbuf)); puts(cntlsendbuf); break; default: goto errout; } /* 忽略的命令直接进入 */ defaultout: cntl->lastcmd = cmd; cntl->status = CS_WAIT_CMD; return 0; trans: if (cntl->status == CS_PORT_RECVD && cntl->dataconn && cntl->dataconn->status == DS_READY) { pid_t pid; struct serv_data_conn *dconnp = cntl->dataconn; dconnp->cmd = cmd; dconnp->filename = params ? strdup(params):NULL; snprintf(cntlsendbuf, LINELEN, "125 Data connection already open; transfer starting.\n"); write(cntl->sockfd, cntlsendbuf, strlen(cntlsendbuf)); printf("%s", cntlsendbuf); do_server_cmd_transfer(dconnp); //transfer_over(cntl); //cntl->status = CS_WAIT_CMD; cntl->status = CS_WAIT_TRANS; dconnp->status = DS_TRANSING; // puts("data conn closed."); return 0; } else { goto errout; } errout: cntl->status = CS_WAIT_CMD; return -1; } static int handle_request(struct serv_cntl_conn *cntl) { int n; char *linerecvd = NULL; if (!cntl) return -1; puts("handle_request"); do { if (!linerecvd) free(linerecvd); n = readline(cntl->sockfd, cntl->line, LINELEN, &cntl->lineused, &linerecvd); if (n == 0) { // connection closed close(cntl->sockfd); fprintf(stdout, "LOG: close socket %d\n", cntl->sockfd); cntl->sockfd = -1; cntl->status = CS_FINISHED; return 0; } else if (n < 0) { /* error receive */ if (errno == EAGAIN || errno == EWOULDBLOCK) /* no data */ break; else { fprintf(stderr, "error receive data : %s\n", strerror(errno)); reset_cntl(cntl); // exit(EXIT_FAILURE); return -1; } } if (linerecvd) { fprintf(stdout, "LOG: received line --> %s\n", linerecvd); handle_line_request(cntl, linerecvd); } } while (n > 0 && linerecvd != NULL); return 0; } /* 1) select one fd 2) accept to get connection, add the connection to pool 3) read request, dispatch */ static void server() { fd_set rfds; int retval, flags, maxfd = 0; struct serv_cntl_conn *curcntl, *lastcntl; /* set NONBLOCK */ // fcntl(servfd, F_SETOWN, getpid()); flags = fcntl(servfd, F_GETFL); fcntl(servfd, F_SETFL, flags|O_NONBLOCK); fprintf(stdout,"server for loop\n"); connlen = 0; cntl_head = NULL; for (;;) { FD_ZERO(&rfds); FD_SET(servfd, &rfds); maxfd = servfd; lastcntl = NULL; for (curcntl = cntl_head; curcntl; ) { /* 删除已经关闭的客户端 */ if (curcntl->status == CS_FINISHED) { struct serv_cntl_conn *next = curcntl->next; if (lastcntl) { lastcntl->next = next; } else { cntl_head = next; } if (curcntl->lastparams) free(curcntl->lastparams); if (curcntl->cwd) free(curcntl->cwd); free(curcntl); curcntl = next; connlen --; continue; } int fd = curcntl->sockfd; FD_SET(fd, &rfds); maxfd = maxfd < fd ? fd : maxfd; lastcntl = curcntl; curcntl = curcntl->next; } while (select(maxfd+1, &rfds, NULL, NULL, NULL) == -1) { if (errno == EINTR) { continue; } else { fprintf(stderr,"select(): %s\n", strerror(errno)); exit(EXIT_FAILURE); } } for (curcntl = cntl_head; curcntl; curcntl = curcntl->next) { int fd = curcntl->sockfd; if (FD_ISSET(fd, &rfds)) { fprintf(stdout,"fd %d is set\n", fd); handle_request(curcntl); printf("hand fd %d ok\n",fd); } } if (FD_ISSET(servfd, &rfds)) { /*new connect*/ struct serv_cntl_conn *servconn; servconn = accept_new_client(servfd); if (servconn != NULL) { if (connlen < MAX_CONN) { servconn->next = cntl_head; cntl_head = servconn; connlen ++; fprintf(stdout, "accepted, fd = %d, connlen = %d\n", servconn->sockfd,connlen); } else { fprintf(stderr, "reach max connection size\n"); shutdown(servconn->sockfd, SHUT_RDWR); close(servconn->sockfd); free(servconn); } } } } } int main(int argc, const char* argv[]) { int err; pthread_t tid; strcpy(homedir, "/home/kuangf/ftptmp/"); init_server(); #if 1 if (signal(SIGCHLD, sig_child) == SIG_ERR) { fprintf(stderr, "signal error\n"); } #endif server(); fprintf(stdout, "server out\n"); return 0; }
试试其它关键字
ftp
同语言下
.
获取手机通讯录 iOS去除数字以外的所有字符
.
异步加载音乐等资源
.
交通罚单管理系统
.
freemark实现,简单的替换
.
计算斐波那契数列
.
base64解码 包括解码长度
.
图像显示
.
冒泡排序
.
输入十进制数,输出指定进制
.
链式栈
可能有用的
.
C#实现的html内容截取
.
List 切割成几份 工具类
.
SQL查询 多列合并成一行用逗号隔开
.
一行一行读取txt的内容
.
C#动态修改文件夹名称(FSO实现,不移动文件)
.
c# 移动文件或文件夹
.
c#图片添加水印
.
Java PDF转换成图片并输出给前台展示
.
网站后台修改图片尺寸代码
.
处理大图片在缩略图时的展示
匡峰
贡献的其它代码
(
1
)
.
linux下的简单的ftp实现
Copyright © 2004 - 2024 dezai.cn. All Rights Reserved
站长博客
粤ICP备13059550号-3