miniftp

MiniFtp

一.项目介绍

FTP就是文件传输协议。用于互联网双向传输,控制文件下载空间在服务器复制文件从本地计算机或本 地上传文件复制到服务器上的空间,miniftp实现了FTP传输的主要功能,简洁高效;

二.环境配置

1.下载vsptpd工具

yum install vsftpd -y

2.启动vsftpd

systemctl status vsftpd //查看状态
systemctl start vsftpd //打开工具
systemctl stop vsftpd 
systemctl restart vsftpd 
在/ect/vsftpd/vsftpd.conf 修改配置文件

3.配置Windows下的Editplus

chmod 给予相关文件权限

三.系统框架

1.创建common.h模块
#ifndef _COMMON_H_
#define _COMMON_H

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include<sys/socket.h>
#include<netinnet/in.h>
#include<arpa/inet.h>

#define ERR_EXIT(m) \
   do{\
       prror(m);/
       exit(EXIT_FAILURE);/
     }while(0)
#endif
2.创建系统调用模块
#include"sysutil"
int tcp_server(const char* host ,unsigned short port)
{
	int listenfd;
	listenfd = socket(AF_INET,SOCK_STRERAM,0);//创建套接字,参数分别为IPV4协议版本,字节流数据报,协议类型
	if(listenfd < 0)
		ERR_EXIT("tcp_server);
	struct sockaddr_in addrSer;//套接字参数,服务器地址信息
	addrSer.sin_family = AF_INET;服务器地址域IPV4
	addrSer.sin_port = htons(port);服务器端口号
	addrSer,sin_addr.s_addt = inet_addr(host);服务器IP地址
	int on = 1;
	if(setsockopt(listenfd,SOL_REUSEADDR , &on,sizeof(on)))//设置socket属性
		ERR_EXIT("setsockopt");
    if(bind(listenfd,(struct sockaddr*)&addrSer,sizeof(addrSer)) < 0)
		ERR_EXIT("bind");//绑定套接字
	if(listen(listenfd,SOMAXCONN) < 0)//开始监听,参数为linten操作句柄和接收队列
		ERR_EXIT("listen");

	return listenfd;
	}
    
                 
                 
///
  int tcp_client()
{
	int sock;
	if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		ERR_EXIT("tcp_client");

	if(port > 0)
	{
		int on = 1;
		if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)//设置系统绑定
			ERR_EXIT("setsockopt");

		struct sockaddr_in address;
		address.sin_family = AF_INET;
		address.sin_addr.s_addr = INADDR_ANY;
		address.sin_port = htons(port);
		if(bind(sock, (struct sockaddr*)&address, sizeof(struct sockaddr)) < 0)
			ERR_EXIT("bind 20");
	}

	return sock;
}

const char* statbuf_get_perms(struct stat *sbuf)
{
	//- --- --- ---
	static char perms[] = "----------";
	mode_t mode = sbuf->st_mode;
	switch(mode & S_IFMT)
	{
	case S_IFSOCK:
		perms[0] = 's';
		break;
	case S_IFLNK:
		perms[0] = 'l';
		break;
	case S_IFREG:
		perms[0] = '-';
		break;
	case S_IFBLK:
		perms[0] = 'b';
		break;
	case S_IFDIR:
		perms[0] = 'd';
		break;
	case S_IFCHR:
		perms[0] = 'c';
		break;
	case S_IFIFO:
		perms[0] = 'p';
		break;
	}

	if(mode & S_IRUSR)
		perms[1] = 'r';
	if(mode & S_IWUSR)
		perms[2] = 'w';
	if(mode & S_IXUSR)
		perms[3] = 'x';

	if(mode & S_IRGRP)
		perms[4] = 'r';
	if(mode & S_IWGRP)
		perms[5] = 'w';
	if(mode & S_IXGRP)
		perms[6] = 'x';

	if(mode & S_IROTH)
		perms[7] = 'r';
	if(mode & S_IWOTH)
		perms[8] = 'w';
	if(mode & S_IXOTH)
		perms[9] = 'x';

	return perms;
}

const char* statbuf_get_date(struct stat *sbuf)
{
	static char datebuf[64] = {0};
	time_t file_time = sbuf->st_mtime;
	struct tm *ptm = localtime(&file_time);
	strftime(datebuf, 64, "%b %e %H:%M",  ptm);
	return datebuf;
}

void send_fd(int sock_fd, int fd)//发送操作描述符
{
	int ret;
	struct msghdr msg;
	struct cmsghdr *p_cmsg;
	struct iovec vec;
	char cmsgbuf[CMSG_SPACE(sizeof(fd))];
	int *p_fds;
	char sendchar = 0;
	msg.msg_control = cmsgbuf;
	msg.msg_controllen = sizeof(cmsgbuf);
	p_cmsg = CMSG_FIRSTHDR(&msg);
	p_cmsg->cmsg_level = SOL_SOCKET;
	p_cmsg->cmsg_type = SCM_RIGHTS;
	p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
	p_fds = (int*)CMSG_DATA(p_cmsg);
	*p_fds = fd;

	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	msg.msg_iov = &vec;
	msg.msg_iovlen = 1;
	msg.msg_flags = 0;

	vec.iov_base = &sendchar;
	vec.iov_len = sizeof(sendchar);
	ret = sendmsg(sock_fd, &msg, 0);
	if (ret != 1)
		ERR_EXIT("sendmsg");
}

int recv_fd(const int sock_fd)//接收操作描述符
{
	int ret;
	struct msghdr msg;
	char recvchar;
	struct iovec vec;
	int recv_fd;
	char cmsgbuf[CMSG_SPACE(sizeof(recv_fd))];
	struct cmsghdr *p_cmsg;
	int *p_fd;
	vec.iov_base = &recvchar;
	vec.iov_len = sizeof(recvchar);
	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	msg.msg_iov = &vec;
	msg.msg_iovlen = 1;
	msg.msg_control = cmsgbuf;
	msg.msg_controllen = sizeof(cmsgbuf);
	msg.msg_flags = 0;

	p_fd = (int*)CMSG_DATA(CMSG_FIRSTHDR(&msg));
	*p_fd = -1;  
	ret = recvmsg(sock_fd, &msg, 0);
	if (ret != 1)
		ERR_EXIT("recvmsg");

	p_cmsg = CMSG_FIRSTHDR(&msg);
	if (p_cmsg == NULL)
		ERR_EXIT("no passed fd");


	p_fd = (int*)CMSG_DATA(p_cmsg);
	recv_fd = *p_fd;
	if (recv_fd == -1)
		ERR_EXIT("no passed fd");

	return recv_fd;
}
3.创建会话session模块
#include"session.h"

void begin_session(session_t *sess)
{
	//初始化父子进程通讯通道
	priv_sock_init(sess);

	pid_t pid = fork();
	if(pid == -1)
		ERR_EXIT("fork");
	if(pid == 0)
	{
		//ftp 服务进程
		priv_sock_set_child_context(sess);
		handle_child(sess);
	}
	else
	{
		//nobody 进程
		priv_sock_set_parent_context(sess);
		
		//把root进程更改进程名为nobody
		struct passwd *pw = getpwnam("nobody");
		if(pw == NULL)
			ERR_EXIT("getpwname");
		if(setegid(pw->pw_gid) < 0)
			ERR_EXIT("setegid");
		if(seteuid(pw->pw_uid) < 0)
			ERR_EXIT("seteuid");

		handle_parent(sess);
	}
}
4.创建服务进程模块
#include"ftpproto.h"
#include"ftpcodes.h"
#include"str.h"

void ftp_reply(session_t *sess, int code, const char *text)
{
	char buf[MAX_BUFFER_SIZE] = {0};
	sprintf(buf, "%d %s\r\n", code, text);
	send(sess->ctrl_fd, buf, strlen(buf), 0);
}//回复命令

/
//命令映射机制
//操作函数
static void do_user(session_t *sess);
static void do_pass(session_t *sess);
static void do_syst(session_t *sess);
static void do_feat(session_t *sess);//回复内容服务器功能
static void do_pwd (session_t *sess);//显示当前目录
static void do_type(session_t *sess);
static void do_port(session_t *sess);
static void do_list(session_t *sess);

typedef struct ftpcmd
{
	const char *cmd;
	void(*cmd_handler)(session_t *sess);
}ftpcmd_t;//回应结构体

//命令映射表
static ftpcmd_t ctrl_cmds[] = 
{
	{"USER",  do_user},
	{"PASS",  do_pass},
	{"SYST",  do_syst},
	{"FEAT",  do_feat},
	{"PWD",   do_pwd },
	{"TYPE",  do_type},
	{"PORT",  do_port},
	{"LIST",  do_list}
};

/


//ftp 服务进程
void handle_child(session_t *sess)
{
	ftp_reply(sess, FTP_GREET, "(bit65 miniftp 1.0 )");

	int ret;
	while(1)
	{
		//不停的等待客户端的命令并进行处理
		memset(sess->cmdline, 0, MAX_COMMAND_LINE);
		memset(sess->cmd, 0, MAX_COMMAND);
		memset(sess->arg, 0, MAX_ARG);
		ret = recv(sess->ctrl_fd, sess->cmdline, MAX_COMMAND_LINE, 0);//回复命令
		if(ret == -1)
			ERR_EXIT("readline");
		else if(ret == 0)
			exit(EXIT_SUCCESS);

		str_trim_crlf(sess->cmdline);
		//printf("cmdline = %s\n", sess->cmdline);
		str_split(sess->cmdline, sess->cmd, sess->arg, ' ');
		//printf("cmd = %s\n", sess->cmd);
		//printf("arg = %s\n", sess->arg);

		int table_size = sizeof(ctrl_cmds) / sizeof(ftpcmd_t);
		int i;
		for(i=0; i<table_size; ++i)//遍历寻找命令对应函数
		{
			if(strcmp(sess->cmd, ctrl_cmds[i].cmd) == 0)
			{
				if(ctrl_cmds[i].cmd_handler != NULL)
					ctrl_cmds[i].cmd_handler(sess);
				else
					ftp_reply(sess, FTP_COMMANDNOTIMPL, "Unimplement command.");
				break;
			}
		}

		if(i >= table_size)//没有找到
			ftp_reply(sess, FTP_BADCMD, "Unknown command.");
	}
}

//USER abc
static void do_user(session_t *sess)
{
	struct passwd *pwd = getpwnam(sess->arg);
	if(pwd != NULL)
		sess->uid = pwd->pw_uid;

	ftp_reply(sess, FTP_GIVEPWORD, "Please specify the password.");
}//do_user函数回复内容

//PASS 123abc
static void do_pass(session_t *sess)
{
	//鉴权
	struct passwd *pwd = getpwuid(sess->uid);
	if(pwd == NULL)
	{
		ftp_reply(sess, FTP_LOGINERR, "Login incorrect.");
		return;
	}
	
	struct spwd *spd = getspnam(pwd->pw_name);
	if(spd == NULL)
	{
		ftp_reply(sess, FTP_LOGINERR, "Login incorrect.");
		return;
	}

	char *encry_pwd = crypt(sess->arg, spd->sp_pwdp);
	if(strcmp(encry_pwd, spd->sp_pwdp) != 0)
	{
		ftp_reply(sess, FTP_LOGINERR, "Login incorrect.");
		return;
	}
	
	setegid(pwd->pw_gid);
	seteuid(pwd->pw_uid);
	chdir(pwd->pw_dir);

	ftp_reply(sess, FTP_LOGINOK, "Login successful.");
}

static void do_syst(session_t *sess)
{
	ftp_reply(sess, FTP_SYSTOK, "UNIX Type: L8");
}

static void do_feat(session_t *sess)//do_feat回复内容服务器功能
{
	send(sess->ctrl_fd, "211-Features:\r\n" ,strlen("211-Features:\r\n"), 0);
	send(sess->ctrl_fd, " EPRT\r\n", strlen(" EPRT\r\n"), 0);
	send(sess->ctrl_fd, " EPSV\r\n", strlen(" EPSV\r\n"), 0);
	send(sess->ctrl_fd, " MDTM\r\n", strlen(" MDTM\r\n"), 0);
	send(sess->ctrl_fd, " PASV\r\n", strlen(" PASV\r\n"), 0);
	send(sess->ctrl_fd, " REST STREAM\r\n", strlen(" REST STREAM\r\n"), 0);
	send(sess->ctrl_fd, " SIZE\r\n", strlen(" SIZE\r\n"), 0);
	send(sess->ctrl_fd, " TVFS\r\n", strlen(" TVFS\r\n"), 0);
	send(sess->ctrl_fd, " UTF8\r\n", strlen(" UTF8\r\n"), 0);
	send(sess->ctrl_fd, "211 End\r\n", strlen("211 End\r\n"), 0);
}

static void do_pwd (session_t *sess)//显示当前目录
{
	char buffer[MAX_BUFFER_SIZE] = {0};
	getcwd(buffer, MAX_BUFFER_SIZE);   // 获取工作目录
	char msg[MAX_BUFFER_SIZE] = {0};
	sprintf(msg, "\"%s\"", buffer);    //给内容加上“”
	ftp_reply(sess, FTP_PWDOK, msg);
}

static void do_type(session_t *sess)//传输方式
{
	//TYPE A  or  TYPE I
	if(strcmp(sess->arg, "A") == 0)//ASCII码模式
	{
		sess->is_ascii = 1;
		ftp_reply(sess, FTP_TYPEOK, "Switching to ASCII mode.");
	}
	else if(strcmp(sess->arg, "I") == 0)//二进制模式
	{
		sess->is_ascii = 0;
		ftp_reply(sess, FTP_TYPEOK, "Switching to Binary mode.");
	}
	else//不制持
		ftp_reply(sess, FTP_BADCMD, "Unrecognised TYPE command.");
}

static void do_port(session_t *sess)//发送IP地址及端口号
{
	//PORT 192,168,232,1,7,34
	unsigned int v[6] = {0};
	sscanf(sess->arg, "%u,%u,%u,%u,%u,%u", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5]);

	sess->port_addr = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
	unsigned char *p = (unsigned char *)&sess->port_addr->sin_port;//端口号映射
	p[0] = v[4];
	p[1] = v[5];

	p = (unsigned char *)&sess->port_addr->sin_addr;//IP地址映射
	p[0] = v[0];
	p[1] = v[1];
	p[2] = v[2];
	p[3] = v[3];

	sess->port_addr->sin_family = AF_INET;//地址域IPV4
	ftp_reply(sess, FTP_PORTOK, "command successful. Consider using PASV.");//发送成功消息
}

static void do_pasv(session_t *sess)
{
	// 227 Entering Passive Mode (192,168,232,10,140,176).
	char ip[16] = "192.168.232.10"; //服务器的IP
	sess->pasv_listen_fd = tcp_server(ip, 0);//port为0代表生成临时端口号

	struct sockaddr_in address;
	socklen_t addrlen = sizeof(struct sockaddr);
	if(getsockname(sess->pasv_listen_fd, (struct sockaddr*)&address, &addrlen) < 0)//获取套接字信息
		ERR_EXIT("getsockname");

	unsigned short port = ntohs(address.sin_port);//字节序转化

	int v[4] = {0};
	sscanf(ip, "%u.%u.%u.%u", &v[0], &v[1], &v[2], &v[3]);//将字符串格式化
	char msg[MAX_BUFFER_SIZE] = {0};
	sprintf(msg, "Entering Passive Mode (%u,%u,%u,%u,%u,%u).", v[0],v[1],v[2],v[3], port>>8, port&0x00ff);//输出格式>>取高八位,&x00ff取低八位
	ftp_reply(sess, FTP_PASVOK, msg);
}




int port_active(session_t *sess)//判断port模式是否被激活
{
	if(sess->port_addr)
		return 1;
	return 0;
}

int pasv_active(session_t *sess)//判断pasv模式是否激活
{
	if(sess->pasv_listen_fd != -1)
		return 1;
	return 0;
}
int get_port_fd(session_t *sess)
{
	int ret = 1;
	//ftp 向 nobody 发起通讯
	priv_sock_send_cmd(sess->child_fd, PRIV_SOCK_GET_DATA_SOCK);//向对方进程发送指令
	unsigned short port = ntohs(sess->port_addr->sin_port);//端口号
	char *ip = inet_ntoa(sess->port_addr->sin_addr);//IP地址

	//发送port端口号及ip地址
	priv_sock_send_int(sess->child_fd, (int)port);
	priv_sock_send_buf(sess->child_fd, ip, strlen(ip));

	char res = priv_sock_get_result(sess->child_fd);
	if(res == PRIV_SOCK_RESULT_BAD)
		ret = 0;
	else if(res == PRIV_SOCK_RESULT_OK)//连接成功返回数据连接操作句柄
		sess->data_fd = priv_sock_recv_fd(sess->child_fd);
	return ret;
}
int get_pasv_fd(session_t *sess)
{
	int ret = 1;
	priv_sock_send_cmd(sess->child_fd, PRIV_SOCK_PASV_ACCEPT);//发送连接命令
	char res = priv_sock_get_result(sess->child_fd);
	if(res == PRIV_SOCK_RESULT_BAD)
		ret = 0;
	else if(res == PRIV_SOCK_RESULT_OK)
		sess->data_fd = priv_sock_recv_fd(sess->child_fd);
	
	return ret;
}
int get_transfer_fd(session_t *sess)//建立连接
{
	if(!port_active(sess) && !pasv_active(sess))
	{
		ftp_reply(sess, FTP_BADSENDCONN,"Use PORT or PASV first.");
		return 0;
	}

	int ret = 1;
	//port
	if(port_active(sess))
	{
		if(!get_port_fd(sess))
			ret = 0;
	}

	//pasv
	if(pasv_active(sess))
	{
		if(!get_pasv_fd(sess))
			ret = 0;
	}

	if(sess->port_addr)
	{
		free(sess->port_addr);
		sess->port_addr = NULL;
	}

	return ret;
}

static void list_common(session_t *sess)//列表显示
{
	DIR *dir = opendir(".");//打开当前目录
	if(dir == NULL)
		return;

	//drwxr-xr-x    3 1000     1000           30 Sep 09  2019 Desktop
	char buf[MAX_BUFFER_SIZE] = {0};

	struct stat sbuf; //用于保存文件的属性
	struct dirent *dt;
	while((dt = readdir(dir)) != NULL)
	{
		if(stat(dt->d_name, &sbuf) < 0)
			continue;
		if(dt->d_name[0] == '.')  //过滤掉隐藏文件
			continue;

		memset(buf, MAX_BUFFER_SIZE, 0);
		//先组合权限
		const char *perms = statbuf_get_perms(&sbuf);  //drwxr-xr-x
		int offset = 0;
		offset += sprintf(buf, "%s", perms);
		offset += sprintf(buf+offset, "%3d %-8d %-8d %8u", sbuf.st_nlink, sbuf.st_uid, sbuf.st_gid, sbuf.st_size);
		
		//后组合时间日期
		const char *pdate = statbuf_get_date(&sbuf);   //Sep 09  2019 
		offset += sprintf(buf+offset, "%s", pdate);
		sprintf(buf+offset, "%s\r\n", dt->d_name);

		//发送数据
		send(sess->data_fd, buf, strlen(buf), 0);
	}
}

static void do_list(session_t *sess)
{
	//1 建立数据连接
	if(get_transfer_fd(sess) == 0)//主动和被动连接
		return;

	//2 回复 150
	ftp_reply(sess, FTP_DATACONN ,"Here comes the directory listing.");

	//3 显示列表
	list_common(sess);


	//4 关闭连接
	close(sess->data_fd);
	sess->data_fd = -1;

	//5 回复 226
	ftp_reply(sess, FTP_TRANSFEROK, "Directory send OK.");
}
5.创建nobody进程模块:
#include"privparent.h"
#include"privsock.h"
#include"session.h"

//获取主动模式数据连接套接字
static void privop_pasv_get_data_sock(session_t *sess); 

//判断是否处于被动模式的激活状态
static void privop_pasv_active(session_t *sess); 

//获取被动模式下的监听端口
static void privop_pasv_listen(session_t *sess);

//获取被动模式下的数据连接套接字
static void privop_pasv_accept(session_t *sess); 
//提升权限
static void minimize_privilege()
{
	//把root进程更改进程名为nobody
	struct passwd *pw = getpwnam("nobody");
	if(pw == NULL)
		ERR_EXIT("getpwname");
	if(setegid(pw->pw_gid) < 0)
		ERR_EXIT("setegid");
	if(seteuid(pw->pw_uid) < 0)
		ERR_EXIT("seteuid");

	struct __user_cap_header_struct cap_header;
	struct __user_cap_data_struct   cap_data;
	memset(&cap_header, 0, sizeof(cap_header));
	memset(&cap_data, 0, sizeof(cap_data));

	cap_header.version = _LINUX_CAPABILITY_VERSION_2;
	cap_header.pid = 0;//代表是root进程

	unsigned int cap_mask = 0;
	cap_mask |= (1 << CAP_NET_BIND_SERVICE);  //0000 0000 0000 0000 0001 0000 0100 0000

	cap_data.effective = cap_data.permitted = cap_mask;
	cap_data.inheritable = 0; // 不继承之前权限
	
	capset(&cap_header, &cap_data);//用于设置权限能力
}

//nobody 进程
void handle_parent(session_t *sess)
{
    minimize_privilege();//提升权限
	char cmd;
	while(1)
	{
		//不停的等待ftp进程的命令
		cmd = priv_sock_get_cmd(sess->parent_fd);
		switch(cmd)
		{
		case PRIV_SOCK_GET_DATA_SOCK:
			privop_pasv_get_data_sock(sess);
			break;
		case PRIV_SOCK_PASV_ACTIVE:
			privop_pasv_active(sess);
			break;
		case PRIV_SOCK_PASV_LISTEN:
			privop_pasv_listen(sess);
			break;
		case PRIV_SOCK_PASV_ACCEPT:
			privop_pasv_accept(sess);
			break;
		}
	}
}
static void privop_pasv_get_data_sock(session_t *sess)
{
	unsigned short port = (unsigned short)priv_sock_get_int(sess->parent_fd);
	char ip[16] = {0};
	priv_sock_recv_buf(sess->parent_fd, ip, sizeof(ip));

	struct sockaddr_in address;
	address.sin_family = AF_INET;
	address.sin_port = htons(port);
	address.sin_addr.s_addr = inet_addr(ip);

	int fd = tcp_client(20);  //绑定20端口
	if(fd == -1)
	{
		priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_BAD);
		return;
	}
	if(connect(fd, (struct sockaddr*)&address, sizeof(address)) < 0)
	{
		close(fd);
		priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_BAD);
		return;
	}

	priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_OK);
	priv_sock_send_fd(sess->parent_fd,  fd);
	close(fd);
}

static void privop_pasv_active(session_t *sess)
{
	int active;
	if(sess->pasv_listen_fd != -1)
		active = 1;
	else
		active = 0;
	priv_sock_send_int(sess->parent_fd, active);
}

static void privop_pasv_listen(session_t *sess)
{
	char *ip = "192.168.232.10"; //暂且写死
	sess->pasv_listen_fd = tcp_server(ip, 0); //传端口0表示绑定临时端口
	
	struct sockaddr_in address;
	socklen_t addrlen = sizeof(struct sockaddr);
	if(getsockname(sess->pasv_listen_fd, (struct sockaddr*)&address, &addrlen) < 0)
		ERR_EXIT("getsockname");

	unsigned short port = ntohs(address.sin_port);
	priv_sock_send_int(sess->parent_fd, (int)port);
}

static void privop_pasv_accept(session_t *sess)
{
	int fd = accept(sess->pasv_listen_fd, 0, 0);
	close(sess->pasv_listen_fd);
	sess->pasv_listen_fd = -1;

	if(fd == -1)
	{
		priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_BAD);
		return;
	}

	priv_sock_send_result(sess->parent_fd, PRIV_SOCK_RESULT_OK);
	priv_sock_send_fd(sess->parent_fd, fd);
	close(fd);
}
6.主进程模块
#include"common.h"
#include"sysutil.h"
#include"session.h"
int main()
{
	session_t sess =
	{
		-1;//控制连接
	};
    int listenfd = tcp_server("192.168.219.131",8080);//开始监听
	int sockConn;
	struct sockaddr_in addrCli;
    socklen_t sddrlen;
	while(1)
	{
       if(sockConn = accpet(listenfd,(struct sockaddr*)&addrCli, &addrlen) < 0)//接收连接参数为客户端地址信息,客户端地址长度
		   ERR_EXIT("accpet"); 
	   pid_t pid = fork();//创建进程
		   if(pid == -1)//创建失败
		   ERR_EXIT("fork");
	       if(pid == 0)
		{
			   close(listenfd);
			   //创建会话
			  sess.ctrl_fd = sockConn;//控制连接
			  begin_session(&sess);
               exit(EXIT_SUCCESS);
			   //子进程
		}
           else
		{
			   close(sockConn);//父进程
		}
	}
	close(listenfd);
	return 0;
}
//
7.创建markfile

8.创建字符操作模块str
#include"str.h"

void str_trim_crlf(char *str)
{
	assert(str != NULL);
	char *p = str + (strlen(str)-1);
	while(*p=='\n' || *p=='\r')
		*p-- = '\0';
}//替换\r\n字符

void str_split(const char *str, char *left, char *right, char c)
{
	assert(str != NULL);
	char *pos = strchr(str, c);
	if(pos == NULL)
		strcpy(left, str);
	else
	{
		strncpy(left, str, pos-str);
		strcpy(right, pos+1);
	}
}//字符串分割
9.创建进程通信privsock.h
#include"privsock.h"
#include"sysutil.h"

void priv_sock_init(session_t *sess)//初始化
{
	int sockfds[2];
	if(socketpair(PF_UNIX, SOCK_STREAM, 0, sockfds) < 0)//建立一个双向的传输方式
		ERR_EXIT("socketpair");
	sess->child_fd = sockfds[1];
	sess->parent_fd = sockfds[0];
}
void priv_sock_close(session_t *sess)//关闭传输接口
{
	if(sess->parent_fd != -1)
	{
		close(sess->parent_fd);
		sess->parent_fd = -1;
	}
	if(sess->child_fd != -1)
	{
		close(sess->child_fd);
		sess->child_fd = -1;
	}
}
void priv_sock_set_parent_context(session_t *sess)
{
	if(sess->child_fd != -1)
	{
		close(sess->child_fd);
		sess->child_fd = -1;
	}
}
void priv_sock_set_child_context(session_t *sess)
{
	if(sess->parent_fd != -1)
	{
		close(sess->parent_fd);
		sess->parent_fd = -1;
	}
}

void priv_sock_send_cmd(int fd, char cmd)//发送命令
{
	int ret = send(fd, &cmd, sizeof(cmd), 0);
	if(ret != sizeof(cmd))
		ERR_EXIT("priv_sock_send_cmd error.");
}
char priv_sock_get_cmd(int fd)//接收命令
{
	char cmd;
	int ret;
	ret = recv(fd, &cmd, sizeof(cmd), 0);
	if(ret == 0)
	{
		printf("ftp process exit.\n");
		exit(EXIT_SUCCESS);
	}
	if(ret != sizeof(cmd))
		ERR_EXIT("priv_sock_get_cmd error.");
	return cmd;
}

void priv_sock_send_result(int fd, char res)//发送处理结果
{
	int ret = send(fd, &res, sizeof(res), 0);
	if(ret != sizeof(res))
		ERR_EXIT("priv_sock_send_result error.");
}
char priv_sock_get_result(int fd)//接收处理结果
{
	char res;
	int ret;
	ret = recv(fd, &res, sizeof(res), 0);
	if(ret == 0)
	{
		printf("ftp process exit.\n");
		exit(EXIT_SUCCESS);
	}
	if(ret != sizeof(res))
		ERR_EXIT("priv_sock_get_result error.");
	return res;
}

void priv_sock_send_int(int fd, int the_int)//发送整型数据
{
	int ret = send(fd, &the_int, sizeof(the_int), 0);
	if(ret != sizeof(the_int))
		ERR_EXIT("priv_sock_send_int error.");
}
int priv_sock_get_int(int fd)//接收整型数据
{
	int res;
	int ret;
	ret = recv(fd, &res, sizeof(res), 0);
	if(ret == 0)
	{
		printf("ftp process exit.\n");
		exit(EXIT_SUCCESS);
	}
	if(ret != sizeof(res))
		ERR_EXIT("priv_sock_get_int error.");
	return res;
}

void priv_sock_send_buf(int fd, const char *buf, unsigned int len)//发送字符串类型
{
	priv_sock_send_int(fd, len);
	int ret = send(fd, buf, len, 0);
	if(ret != len)
		ERR_EXIT("priv_sock_send_buf error.");
}
void priv_sock_recv_buf(int fd, char *buf, unsigned int len)//接收字符串类型
{
	unsigned int recv_len = priv_sock_get_int(fd);
	int ret = recv(fd, buf, recv_len, 0);
	if(ret != recv_len)//判断接收长度是否一直
		ERR_EXIT("priv_sock_recv_buf error.");
}

void priv_sock_send_fd(int sock_fd, int fd)
{
	send_fd(sock_fd, fd);
}
int priv_sock_recv_fd(int sock_fd)
{
	return recv_fd(sock_fd);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值