📄 myftp_serv.c
字号:
#include "myftp_cmd_string.h"
#include "myftp_state_machine.h"
#include "mystr.h"
const char* myftp_pid_file="myftp_pid.pid";//存放服务器主进程的pid文件
enum EVmyftpcmdflags
{
start_cmd = 1,
stop_cmd,
restart_cmd,
undefine_cmd
};
void init_ftp_daemon();
enum EVmyftpcmdflags myftp_serv_cmd_trans(char* argv);
enum EVmyftpcmdflags myftp_chk_cmd(int argc, char* argv);
int myftp_read_pidfile(char* pid_str);
int myftp_call_popen(char* pid_str,char* pid_val);
int myftp_if_running();
int myftp_is_pidfile_exist();
void myftp_stop();
void myftp_write_pid_to_file();
void myftp_creat_pidfile();
void myftp_start();
void myftp_arg_handler(enum EVmyftpcmdflags cmd_enum);
void myftp_getpeername(int clientsock_fd, pMYFTP_SESSION p_thesession);
/*======================================================================
function:父进程收尸函数
======================================================================*/
void sig_handle()
{
wait(0);
}
/*======================================================================
function:申请会话空间
======================================================================*/
void myftp_session_malloc(pMYFTP_SESSION* p_thesession)
{
*p_thesession=(pMYFTP_SESSION)malloc(sizeof(MYFTP_SESSION));
if (!(*p_thesession))
{
die("malloc session error!\n");
}
}
/*======================================================================
function:初始化会话空间
======================================================================*/
pMYFTP_SESSION myftp_make_session()
{
pMYFTP_SESSION p_thesession=NULL;
myftp_session_malloc(&p_thesession);
INIT_SESSION(p_thesession);
return p_thesession;
}
/*======================================================================
function:创建服务器监听套接字
======================================================================*/
int myftp_make_listen_socket(pMYFTP_SESSION p_thesession)
{
int listen_fd;
int yes;
MYFTP_SOCKADDR servaddr;
servaddr.un.u_sockaddr_in.sin_family=AF_INET;
servaddr.un.u_sockaddr_in.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.un.u_sockaddr_in.sin_port=htons(myftp_conf.listen_port);
listen_fd=socket(AF_INET,SOCK_STREAM,0);//监听套节字
if (-1==listen_fd)
{
die("socket error.\n");
}
yes=1;
if (setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes))<0)
{
die("setsockopt error\n");
}
if (-1==bind(listen_fd,&servaddr.un.u_sockaddr,sizeof(servaddr)))
{
die("bind error.\n");
}
if (-1==listen(listen_fd,LISTEN_BACKLOG))
{
die("listen error.\n");
}
p_thesession->cntl_listen_fd=listen_fd;//将服务器监听套接字存放起来
return listen_fd;
}
/*======================================================================
function:分配存放客户端命令字符串空间,并初始化
======================================================================*/
pMYSTR myftp_make_cmd_str_buf()
{
pMYSTR pcmdline=NULL;
myftp_alloc_mystr(&pcmdline);
INIT_MYSTR(pcmdline);
return pcmdline;
}
/*======================================================================
function:服务器监听超时函数
注:超时值为零,即永远等待,直到有客户连接。
======================================================================*/
void myftp_select_socket(pMYFTP_SESSION p_thesession)
{
int select_result;
FD_ZERO(&p_thesession->read_fd);
FD_SET(p_thesession->cntl_listen_fd,&p_thesession->read_fd);
do
{
select_result=select(p_thesession->cntl_listen_fd+1,&p_thesession->read_fd,0,0,NULL);
} while (select_result < 0 && errno == EINTR);
}
/*======================================================================
function:超时功能函数
======================================================================*/
int myftp_timeout(pMYFTP_SESSION p_thesession)
{
fd_set data_fd_set;
struct timeval timeout;
FD_ZERO(&data_fd_set);
FD_SET(p_thesession->cmd_cntl_fd, &data_fd_set);
int select_rslt=-1;
while (1)
{
timeout.tv_sec=myftp_conf.timeout_val;
timeout.tv_usec=0;
if (!(select_rslt=select(p_thesession->cmd_cntl_fd+1,&data_fd_set,0,0,&timeout)))//超时退出
{
return TRUE;
}
else if (select_rslt <0 && errno==EINTR)
{
continue;
}
else
{
return FALSE;
}
}
}
/*======================================================================
function:ftp服务器主函数
======================================================================*/
void myftp_main_server()
{
int client_addrlen=sizeof(MYFTP_SOCKADDR);
pMYFTP_SESSION p_thesession=myftp_make_session();//创建并初始化会话
pMYSTR pcmdline=myftp_make_cmd_str_buf();//分配命令串的存放空间
int listen_fd=myftp_make_listen_socket(p_thesession);//创建监听套接字
p_thesession->p_cmd_line=pcmdline;
signal(SIGCHLD,sig_handle);
FD_ZERO(&p_thesession->read_fd);
FD_SET(p_thesession->cntl_listen_fd,&p_thesession->read_fd);
while (1)
{
int client_cntl_sockfd;
int fd;
myftp_select_socket(p_thesession);
client_cntl_sockfd=accept(listen_fd,0,&client_addrlen);//控制连接
if(-1==client_cntl_sockfd)
{
die("accept error.\n");
}
write(client_cntl_sockfd,"220 (zjw_mini ftp 0.1)\r\n",strlen("220 (zjw_mini ftp 0.1)\r\n"));
myftp_getpeername(client_cntl_sockfd,p_thesession);
int child_serv=fork();
if (!child_serv)
{
close(listen_fd);
close(p_thesession->cntl_listen_fd);
int is_child_quit = -1,client_count;
while (1)
{
if (myftp_timeout(p_thesession))//如果超时
{
write(p_thesession->cmd_cntl_fd,"421 Timeout.\r\n",strlen("421 Timeout.\r\n"));
break;
}
client_count=read(p_thesession->cmd_cntl_fd,pcmdline->cmd_line,sizeof(pcmdline->cmd_line));
if (client_count < 0 && errno == EINTR)
//之前没有这个判断,会导致当read被子进程\
中断后,读出来的值为空值,从而导致向客户端发送错误信息。并且导致二次传输数据时,\
连接断开。
{
continue;
}
if (!myftp_splite_cmd_line(pcmdline))//分割命令字符串
continue;
is_child_quit=myftp_state_machine_entry(p_thesession);//状态机入口函数
memset(p_thesession->p_cmd_line,0,sizeof(MYSTR));
if (is_child_quit == CHILD_QUIT)//用户执行QUIT命令后
break;
else if(is_child_quit==client_cntl_sockfd)//用户执行REIN命令后
{
memset(p_thesession->user_str, 0, USER_LEN);
memset(p_thesession->passwd_str, 0, PASS_LEN);
}
}
exit(0);
}
close(client_cntl_sockfd);
}
}
/*======================================================================
function:获取客户端ip地址
======================================================================*/
void myftp_getpeername(int clientsock_fd, pMYFTP_SESSION p_thesession)
{
int len=sizeof(MYFTP_SOCKADDR);
int retval=getpeername(clientsock_fd,&p_thesession->remote_addr.un.u_sockaddr,&len);
if (retval)
{
#ifdef __MYDEBUG
die("getpeername error\n");
#endif
}
strcpy(p_thesession->remote_data_ip_str,\
(char*)inet_ntoa(p_thesession->remote_addr.un.u_sockaddr_in.sin_addr));
p_thesession->cmd_cntl_fd=clientsock_fd;//将控制连接套接字保存起来
}
/*======================================================================
function:初始化服务器守护进程
=======================================================================*/
void init_ftp_daemon()
{
pid_t ftp_pid;
ftp_pid=fork();
int i;
if (-1==ftp_pid)
{
die("fork daemon error.\n");
}
else if (0<ftp_pid)
{
exit(0);
}
else if (0==ftp_pid)
{
setsid();
ftp_pid=fork();
if (-1==ftp_pid)
{
die("fork2 daemon error.\n");
}
else if (0<ftp_pid)
{
exit(0);
}
else if(0==ftp_pid)
{
if(!myftp_is_pidfile_exist())
{
myftp_creat_pidfile();
}
myftp_write_pid_to_file();
for(i=3;i < NOFILE;++i)//关闭打开的文件描述符
close(i);
chdir("/");//改变工作目录到/
}
}
}
/*==================================================================
function:解析用户输入的参数
===================================================================*/
enum EVmyftpcmdflags myftp_serv_cmd_trans(char* argv)
{
enum EVmyftpcmdflags cmd_enum;
if (strcmp(argv,cmd_string_start) == 0)
{
cmd_enum = start_cmd;
goto BACK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -