公共部分代码

/*
common.h
*/
#ifndef COMMON_H
#define COMMON_H #include <arpa/inet.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h> #define DEBUG 1
#define MAXSIZE 512
#define CLIENT_PORT_ID 30020 struct command
{
char arg[];
char code[];
}; int socket_create(int port); int socket_accept(int sock_listen); int socket_connect(int port, char *host); int recv_data(int sockfd, char* buf, int bufsize); int send_response(int sockfd, int rc); void trimstr(char *str, int n); void read_input(char* buffer, int size); #endif
/*
common.c
*/
#include "common.h" /**
* 创建监听套接字
* 错误返回 -1,正确返回套接字描述符
*/
int socket_create(int port)
{
int sockfd;
int yes = ;
struct sockaddr_in sock_addr; // 创建套接字
if ((sockfd = socket(AF_INET, SOCK_STREAM, )) < )
{
perror("socket() error");
return -;
} // 设置本地套接字地址
sock_addr.sin_family = AF_INET;
sock_addr.sin_port = htons(port);
sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -)
{
close(sockfd);
perror("setsockopt() error");
return -;
} // 绑定本地套接字地址到套接字
if (bind(sockfd, (struct sockaddr *) &sock_addr, sizeof(sock_addr)) < )
{
close(sockfd);
perror("bind() error");
return -;
} // 将套接字设置为监听状态
if (listen(sockfd, ) < )
{
close(sockfd);
perror("listen() error");
return -;
}
return sockfd;
} /**
* 套接字接受请求
* 错误返回 -1,正确返回新的连接套接字
*/
int socket_accept(int sock_listen)
{
int sockfd;
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
sockfd = accept(sock_listen, (struct sockaddr *) &client_addr, &len); // 等待连接 if (sockfd < )
{
perror("accept() error");
return -;
}
return sockfd;
} /**
* 连接远端主机
* 成功返回套接字描述符,失败返回 -1
*/
int socket_connect(int port, char*host)
{
int sockfd;
struct sockaddr_in dest_addr; /* 创建套接字 */
if ((sockfd = socket(AF_INET, SOCK_STREAM, )) < )
{
perror("error creating socket");
return -;
} /* 设置协议地址 */
memset(&dest_addr, , sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
dest_addr.sin_addr.s_addr = inet_addr(host); /* 在套接字上创建连接 */
if(connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) < )
{
perror("error connecting to server");
return -;
}
return sockfd;
} /**
* 接收数据
* 错误返回 -1,正确返回接收的字节数
*/
int recv_data(int sockfd, char* buf, int bufsize)
{
size_t num_bytes;
memset(buf, , bufsize); /* 调用 recv 函数读取套接字数据 */
num_bytes = recv(sockfd, buf, bufsize, );
if (num_bytes < )
return -; return num_bytes;
} /**
* 去除字符串中的空格和换行符
*/
void trimstr(char *str, int n)
{
int i;
for (i = ; i < n; i++)
{
if (isspace(str[i])) str[i] = ;
if (str[i] == '\n') str[i] = ;
}
} /**
* 发送响应码到 sockfd
* 错误返回 -1,正确返回 0
*/
int send_response(int sockfd, int rc)
{
int conv = htonl(rc);
if (send(sockfd, &conv, sizeof conv, ) < )
{
perror("error sending...\n");
return -;
}
return ;
} /**
* 从命令行中读取输入
*/
void read_input(char* buffer, int size)
{
char *nl = NULL;
memset(buffer, , size); if ( fgets(buffer, size, stdin) != NULL )
{
nl = strchr(buffer, '\n');
if (nl)
*nl = '\0'; // 出现换行符,则将该位置部位'\0'(字符串结尾)
}
}

客户端代码:

/*
ftclient.h
*/
#ifndef FTCLIENT_H
#define FTCLIENT_H #include "../common/common.h" int read_reply(); void print_reply(int rc); int ftclient_read_command(char* buf, int size, struct command *cstruct); int ftclient_get(int data_sock, int sock_control, char* arg); int ftclient_open_conn(int sock_con); int ftclient_list(int sock_data, int sock_con); int ftclient_send_cmd(struct command *cmd); void ftclient_login(); #endif
/*
ftclient.c
*/
#include "ftclient.h" int sock_control; /**
* 接收服务器响应
* 错误返回 -1,正确返回状态码
*/
int read_reply()
{
int retcode = ;
if (recv(sock_control, &retcode, sizeof retcode, ) < )
{
perror("client: error reading message from server\n");
return -;
}
return ntohl(retcode);
} /**
* 打印响应信息
*/
void print_reply(int rc)
{
switch (rc)
{
case :
printf("220 Welcome, server ready.\n");
break;
case :
printf("221 Goodbye!\n");
break;
case :
printf("226 Closing data connection. Requested file action successful.\n");
break;
case :
printf("550 Requested action not taken. File unavailable.\n");
break;
}
} /**
* 解析命令行到结构体
*/
int ftclient_read_command(char* buf, int size, struct command *cstruct)
{
memset(cstruct->code, , sizeof(cstruct->code));
memset(cstruct->arg, , sizeof(cstruct->arg)); printf("ftclient> "); // 输入提示符
fflush(stdout);
read_input(buf, size); // 等待用户输入命令
char *arg = NULL;
arg = strtok (buf," ");
arg = strtok (NULL, " "); if (arg != NULL)
strncpy(cstruct->arg, arg, strlen(arg)); if (strcmp(buf, "list") == )
strcpy(cstruct->code, "LIST"); else if (strcmp(buf, "get") == )
strcpy(cstruct->code, "RETR"); else if (strcmp(buf, "quit") == )
strcpy(cstruct->code, "QUIT"); else
return -; // 不合法 memset(buf, , );
strcpy(buf, cstruct->code); // 存储命令到 buf 开始处 /* 如果命令带有参数,追加到 buf */
if (arg != NULL)
{
strcat(buf, " ");
strncat(buf, cstruct->arg, strlen(cstruct->arg));
}
return ;
} /**
* 实现 get <filename> 命令行
*/
int ftclient_get(int data_sock, int sock_control, char* arg)
{
char data[MAXSIZE];
int size;
FILE* fd = fopen(arg, "w"); // 创建并打开名字为 arg 的文件 /* 将服务器传来的数据(文件内容)写入本地建立的文件 */
while ((size = recv(data_sock, data, MAXSIZE, )) > )
fwrite(data, , size, fd); if (size < )
perror("error\n"); fclose(fd);
return ;
} /**
* 打开数据连接
*/
int ftclient_open_conn(int sock_con)
{
int sock_listen = socket_create(CLIENT_PORT_ID); /* 在控制连接上发起一个 ACK 确认 */
int ack = ;
if ((send(sock_con, (char*) &ack, sizeof(ack), )) < )
{
printf("client: ack write error :%d\n", errno);
exit();
} int sock_conn = socket_accept(sock_listen);
close(sock_listen);
return sock_conn;
} /**
* 实现 list 命令
*/
int ftclient_list(int sock_data, int sock_con)
{
size_t num_recvd;
char buf[MAXSIZE];
int tmp = ; /* 等待服务器启动的信息 */
if (recv(sock_con, &tmp, sizeof tmp, ) < )
{
perror("client: error reading message from server\n");
return -;
} memset(buf, , sizeof(buf)); /* 接收服务器传来的数据 */
while ((num_recvd = recv(sock_data, buf, MAXSIZE, )) > )
{
printf("%s", buf);
memset(buf, , sizeof(buf));
} if (num_recvd < )
perror("error"); /* 等待服务器完成的消息 */
if (recv(sock_con, &tmp, sizeof tmp, ) < )
{
perror("client: error reading message from server\n");
return -;
}
return ;
} /**
* 输入含有命令(code)和参数(arg)的 command(cmd) 结构
* 连接 code + arg,并放进一个字符串,然后发送给服务器
*/
int ftclient_send_cmd(struct command *cmd)
{
char buffer[MAXSIZE];
int rc; sprintf(buffer, "%s %s", cmd->code, cmd->arg); /* 发送命令字符串到服务器 */
rc = send(sock_control, buffer, (int)strlen(buffer), );
if (rc < )
{
perror("Error sending command to server");
return -;
} return ;
} /**
* 获取登录信息
* 发送到服务器认证
*/
void ftclient_login()
{
struct command cmd;
char user[];
memset(user, , ); /* 获取用户名 */
printf("Name: ");
fflush(stdout);
read_input(user, ); /* 发送用户名到服务器 */
strcpy(cmd.code, "USER");
strcpy(cmd.arg, user);
ftclient_send_cmd(&cmd); /* 等待应答码 331 */
int wait;
recv(sock_control, &wait, sizeof wait, ); /* 获得密码 */
fflush(stdout);
char *pass = getpass("Password: "); /* 发送密码到服务器 */
strcpy(cmd.code, "PASS");
strcpy(cmd.arg, pass);
ftclient_send_cmd(&cmd); /* 等待响应 */
int retcode = read_reply();
switch (retcode)
{
case :
printf("Invalid username/password.\n");
exit();
case :
printf("Successful login.\n");
break;
default:
perror("error reading message from server");
exit();
break;
}
} /* 主函数入口 */
int main(int argc, char* argv[])
{
int data_sock, retcode, s;
char buffer[MAXSIZE];
struct command cmd;
struct addrinfo hints, *res, *rp; /* 命令行参数合法性检测 */
if (argc != )
{
printf("usage: ./ftclient hostname port\n");
exit();
} char *host = argv[]; //所要连接的服务器主机名
char *port = argv[]; //所要链接到服务器程序端口号 /* 获得和服务器名匹配的地址 */
memset(&hints, , sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
s = getaddrinfo(host, port, &hints, &res);
if (s != )
{
printf("getaddrinfo() error %s", gai_strerror(s));
exit();
} /* 找到对应的服务器地址并连接 */
for (rp = res; rp != NULL; rp = rp->ai_next)
{
sock_control = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); // 创建控制套接字 if (sock_control < )
continue; if(connect(sock_control, res->ai_addr, res->ai_addrlen)==) // 和服务器连接
break; else
{
perror("connecting stream socket");
exit();
}
close(sock_control);
}
freeaddrinfo(rp); /* 连接成功,打印信息 */
printf("Connected to %s.\n", host);
print_reply(read_reply()); /* 获取用户的名字和密码 */
ftclient_login(); while ()
{ // 循环,直到用户输入 quit /* 得到用户输入的命令 */
if ( ftclient_read_command(buffer, sizeof buffer, &cmd) < )
{
printf("Invalid command\n");
continue; // 跳过本次循环,处理下一个命令
} /* 发送命令到服务器 */
if (send(sock_control, buffer, (int)strlen(buffer), ) < )
{
close(sock_control);
exit();
} retcode = read_reply(); //读取服务器响应(服务器是否可以支持该命令?) if (retcode == ) // 退出命令
{
print_reply();
break;
} if (retcode == )
printf("%d Invalid command.\n", retcode);// 不合法的输入,显示错误信息 else
{
// 命令合法 (RC = 200),处理命令 /* 打开数据连接 */
if ((data_sock = ftclient_open_conn(sock_control)) < )
{
perror("Error opening socket for data connection");
exit();
} /* 执行命令 */
if (strcmp(cmd.code, "LIST") == )
ftclient_list(data_sock, sock_control); else if (strcmp(cmd.code, "RETR") == )
{
if (read_reply() == ) // 等待回复
{
print_reply();
close(data_sock);
continue;
}
ftclient_get(data_sock, sock_control, cmd.arg);
print_reply(read_reply());
}
close(data_sock);
} } // 循环得到更多的用户输入 close(sock_control); // 关闭套接字控制连接
return ;
}

makefile文件

CC := gcc
CFLAGS := -Wall -g -Os SHDIR := ../common OBJS = ftclient.o $(SHDIR)/common.o all: ftclient ftclient: $(OBJS)
@$(CC) -o ftclient $(CFLAGS) $(OBJS) $(OBJS) : %.o: %.c
@$(CC) -c $(CFLAGS) $< -o $@ .PHONY:
clean:
@rm -f *.o ftclient
@rm -f ../common/*.o
@echo Done cleaning

服务端代码:

/*
ftserve.h
*/
#ifndef FTSERVE_H
#define FTSERVE_H #include "../common/common.h" void ftserve_retr(int sock_control, int sock_data, char* filename); int ftserve_list(int sock_data, int sock_control); int ftserve_start_data_conn(int sock_control); int ftserve_check_user(char*user, char*pass); int ftserve_login(int sock_control); int ftserve_recv_cmd(int sock_control, char*cmd, char*arg); void ftserve_process(int sock_control); #endif
/*
ftserve.c
*/ #include "ftserve.h" /* 主函数入口 */
int main(int argc, char *argv[])
{
int sock_listen, sock_control, port, pid; /* 命令行合法性检测 */
if (argc != )
{
printf("usage: ./ftserve port\n");
exit();
} /* 将命令行传进来的服务器端口号(字符串)转换为整数 */
port = atoi(argv[]); /* 创建监听套接字 */
if ((sock_listen = socket_create(port)) < )
{
perror("Error creating socket");
exit();
} /* 循环接受不同的客户机请求 */
while()
{
/* 监听套接字接受连接请求,得到控制套接字,用于传递控制信息 */
if ((sock_control = socket_accept(sock_listen)) < )
break; /* 创建子进程处理用户请求 */
if ((pid = fork()) < )
perror("Error forking child process"); /* 子进程调用 ftserve_process 函数与客户端交互 */
else if (pid == )
{
close(sock_listen); // 子进程关闭父进程的监听套接字
ftserve_process(sock_control);
close(sock_control); //用户请求处理完毕,关闭该套接字
exit();
} close(sock_control); // 父进程关闭子进程的控制套接字
} close(sock_listen); return ;
} /**
* 通过数据套接字发送特定的文件
* 控制信息交互通过控制套接字
* 处理无效的或者不存在的文件名
*/
void ftserve_retr(int sock_control, int sock_data, char* filename)
{
FILE* fd = NULL;
char data[MAXSIZE];
size_t num_read;
fd = fopen(filename, "r"); // 打开文件 if (!fd)
send_response(sock_control, ); // 发送错误码 (550 Requested action not taken) else
{
send_response(sock_control, ); // 发送 okay (150 File status okay)
do
{
num_read = fread(data, , MAXSIZE, fd); // 读文件内容
if (num_read < )
printf("error in fread()\n"); if (send(sock_data, data, num_read, ) < ) // 发送数据(文件内容)
perror("error sending file\n"); }
while (num_read > ); send_response(sock_control, ); // 发送消息:226: closing conn, file transfer successful fclose(fd);
}
} /**
* 响应请求:发送当前所在目录的目录项列表
* 关闭数据连接
* 错误返回 -1,正确返回 0
*/
int ftserve_list(int sock_data, int sock_control)
{
char data[MAXSIZE];
size_t num_read;
FILE* fd; int rs = system("ls -l | tail -n+2 > tmp.txt"); //利用系统调用函数 system 执行命令,并重定向到 tmp.txt 文件
if ( rs < )
{
exit();
} fd = fopen("tmp.txt", "r");
if (!fd)
exit(); /* 定位到文件的开始处 */
fseek(fd, SEEK_SET, ); send_response(sock_control, ); memset(data, , MAXSIZE); /* 通过数据连接,发送tmp.txt 文件的内容 */
while ((num_read = fread(data, , MAXSIZE, fd)) > )
{
if (send(sock_data, data, num_read, ) < )
perror("err"); memset(data, , MAXSIZE);
} fclose(fd); send_response(sock_control, ); // 发送应答码 226(关闭数据连接,请求的文件操作成功) return ;
} /**
* 创建到客户机的一条数据连接
* 成功返回数据连接的套接字
* 失败返回 -1
*/
int ftserve_start_data_conn(int sock_control)
{
char buf[];
int wait, sock_data; if (recv(sock_control, &wait, sizeof wait, ) < )
{
perror("Error while waiting");
return -;
} struct sockaddr_in client_addr;
socklen_t len = sizeof client_addr;
getpeername(sock_control, (struct sockaddr*)&client_addr, &len); // 获得与控制套接字关联的外部地址(客户端地址)
inet_ntop(AF_INET, &client_addr.sin_addr, buf, sizeof(buf)); /* 创建到客户机的数据连接 */
if ((sock_data = socket_connect(CLIENT_PORT_ID, buf)) < )
return -; return sock_data;
} /**
* 用户资格认证
* 认证成功返回 1,否则返回 0
*/
int ftserve_check_user(char*user, char*pass)
{
char username[MAXSIZE];
char password[MAXSIZE];
char *pch;
char buf[MAXSIZE];
char *line = NULL;
size_t num_read;
size_t len = ;
FILE* fd;
int auth = ; fd = fopen(".auth", "r"); //打开认证文件(记录用户名和密码)
if (fd == NULL)
{
perror("file not found");
exit();
} /* 读取".auth" 文件中的用户名和密码,验证用户身份的合法性 */
while ((num_read = getline(&line, &len, fd)) != -)
{
memset(buf, , MAXSIZE);
strcpy(buf, line); pch = strtok (buf," ");
strcpy(username, pch); if (pch != NULL)
{
pch = strtok (NULL, " ");
strcpy(password, pch);
} /* 去除字符串中的空格和换行符 */
trimstr(password, (int)strlen(password)); if ((strcmp(user,username)==) && (strcmp(pass,password)==))
{
auth = ; // 匹配成功,标志变量 auth = 1,并返回
break;
}
}
free(line);
fclose(fd);
return auth;
} /* 用户登录*/
int ftserve_login(int sock_control)
{
char buf[MAXSIZE];
char user[MAXSIZE];
char pass[MAXSIZE];
memset(user, , MAXSIZE);
memset(pass, , MAXSIZE);
memset(buf, , MAXSIZE); /* 获得客户端传来的用户名 */
if ( (recv_data(sock_control, buf, sizeof(buf)) ) == -)
{
perror("recv error\n");
exit();
} int i = ;
int n = ;
while (buf[i] != ) //buf[0-4]="USER"
user[n++] = buf[i++]; /* 用户名正确,通知用户输入密码 */
send_response(sock_control, ); /* 获得客户端传来的密码 */
memset(buf, , MAXSIZE);
if ( (recv_data(sock_control, buf, sizeof(buf)) ) == -)
{
perror("recv error\n");
exit();
} i = ;
n = ;
while (buf[i] != ) // buf[0 - 4] = "PASS"
pass[n++] = buf[i++]; return (ftserve_check_user(user, pass)); // 用户名和密码验证,并返回
} /* 接收客户端的命令并响应,返回响应码 */
int ftserve_recv_cmd(int sock_control, char*cmd, char*arg)
{
int rc = ;
char buffer[MAXSIZE]; memset(buffer, , MAXSIZE);
memset(cmd, , );
memset(arg, , MAXSIZE); /* 接受客户端的命令 */
if ((recv_data(sock_control, buffer, sizeof(buffer)) ) == -)
{
perror("recv error\n");
return -;
} /* 解析出用户的命令和参数 */
strncpy(cmd, buffer, );
char *tmp = buffer + ;
strcpy(arg, tmp); if (strcmp(cmd, "QUIT")==)
rc = ; else if ((strcmp(cmd, "USER") == ) || (strcmp(cmd, "PASS") == ) || (strcmp(cmd, "LIST") == ) || (strcmp(cmd, "RETR") == ))
rc = ; else
rc = ; // 无效的命令 send_response(sock_control, rc);
return rc;
} /* 处理客户端请求 */
void ftserve_process(int sock_control)
{
int sock_data;
char cmd[];
char arg[MAXSIZE]; send_response(sock_control, ); // 发送欢迎应答码 /* 用户认证 */
if (ftserve_login(sock_control) == ) // 认证成功
send_response(sock_control, );
else
{
send_response(sock_control, ); // 认证失败
exit();
} /* 处理用户的请求 */
while ()
{
/* 接收命令,并解析,获得命令和参数 */
int rc = ftserve_recv_cmd(sock_control, cmd, arg); if ((rc < ) || (rc == )) // 用户输入命令 "QUIT"
break; if (rc == )
{
/* 创建和客户端的数据连接 */
if ((sock_data = ftserve_start_data_conn(sock_control)) < )
{
close(sock_control);
exit();
} /* 执行指令 */
if (strcmp(cmd, "LIST")==)
ftserve_list(sock_data, sock_control); else if (strcmp(cmd, "RETR")==)
ftserve_retr(sock_control, sock_data, arg); close(sock_data);// 关闭连接
}
}
}

里面还有一个保存密码账户文件.auth,这里就不列出。服务端的makefile和客户端makefile一样,只需要修改一下程序名及相关依赖名即可。

C语言实现FTP服务器的更多相关文章

  1. 使用FileZilla等软件搭建ftp服务器

    FTP的全称是File Transfer Protocol(文件传输协议).顾名思义,就是专门用来传输文件的协议. FTP服务器,则是在互联网上提供存储空间的计算机,它们依照FTP协议提供服务.简单地 ...

  2. 什么是FTP服务器

    FTP服务器,则是在互联网上提供存储空间的计算机,它们依照FTP协议提供服务. FTP的全称是File Transfer Protocol(文件传输协议).顾名思义,就是专门用来传输文件的协议.简单地 ...

  3. 用PHP实现一个高效安全的ftp服务器(一)

    摘要: 本文主要阐述使用PHP的swoole扩展实现ftp服务器,同时扩展ftp服务器个性化功能和安全性.真正实现一个自己完全掌控的ftp服务器,可以个性化定制的ftp服务器. 正文: FTP服务器想 ...

  4. swift之向ftp服务器传文件

    在 mac 上如何使用 xcode, swift 语言开发一个向 ftp 服务器上传文件的工具? 使用的是第三方库 Rebekka,下载地址为:https://github.com/Constanti ...

  5. Linux 安装及配置 Nginx + ftp 服务器

    Nginx 安装及配置 一.Nginx 简介: Nginx("engine x") 是一款是由俄罗斯的程序设计师 Igor Sysoev 所开发高性能的 Web和 反向代理服务器, ...

  6. day-1 用python编写一个简易的FTP服务器

    从某宝上购买了一份<Python神经网络深度学习>课程,按照视频教程,用python语言,写了一个简易的FTP服务端和客户端程序,以前也用C++写过聊天程序,编程思路差不多,但是pytho ...

  7. 【RL-TCPnet网络教程】第36章 RL-TCPnet之FTP服务器

    第36章      RL-TCPnet之FTP服务器 本章节为大家讲解RL-TCPnet的FTP服务器应用,学习本章节前,务必要优先学习第35章的FTP基础知识.有了这些基础知识之后,再搞本章节会有事 ...

  8. Linux学习笔记之十————Linux常用服务器构建之ftp服务器

    p服务器介绍 FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”. 用于Internet上的控制文件的双向传输. 同时,它也是一个应用程序(Ap ...

  9. FileZilla等软件搭建ftp服务器

    一.常用的几款ftp服务器软件介绍 1.1 Server-U Serv-U是一种被广泛运用的FTP服务器端软件,支持3x/9x/ME/NT/2K/2000/xp等全Windows系列.可以设定多个FT ...

随机推荐

  1. js 实现 promise

    本文仅用于个人技术记录,如误导他人,概不负责. 本文有参考其他文章,不过地址忘了~~~. ======================================================= ...

  2. c++小学期大作业攻略(五)基于QSS的样式美化

    这回真的是最后一篇了. 前面说过,我们开发过程中暂时不搭理样式问题,等最后再一起处理,那么现在就是最后处理时刻了!看到网上说QSS跟CSS差不多,我还觉得自己可以干回老本行了,结果用起来发现,QSS是 ...

  3. log4j2记录日志到数据库(完美支持mysql使用DruidDataSource)

    引用 log4j-core-2.12.1.jar log4j-web-2.12.1.jar 1:配置数据源 2:调用类 3:写入

  4. vue简介、入门、模板语法

    在菜鸟教程上面学习的vue.js.同时结合vue中文文档网站,便于自己记录. vueAPI网站:API 1. 简介 Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的渐进式框 ...

  5. maven的基础入门

    Maven是Java世界中一个很好使的项目管理工具,关于[好使]这个特性从项目的使用量上就能体现出来,虽然说现在有更好使的Gradle,但是Maven的地位也不会那么轻易被撼动,支持者还是多多. Ma ...

  6. Spring Boot2.0以上版本EmbeddedServletContainerCustomizer被WebServerFactoryCustomizer替代

    在Spring Boot2.0以上配置嵌入式Servlet容器时EmbeddedServletContainerCustomizer类不存在,经网络查询发现被WebServerFactoryCusto ...

  7. 《 .NET并发编程实战》阅读指南 - 第11章

    先发表生成URL以印在书里面.等书籍正式出版销售后会公开内容.

  8. 第二篇Scrum冲刺博客

    第二篇Scrum冲刺博客 一.站立式会议 提供当天站立式会议照片一张 二.每个人的工作 成员 已完成工作 明天计划完成的工作 遇到的困难 林剑峰 初步学习小程序的编写.博客园的撰写 初步完成用户界面 ...

  9. 生成Uuid工具类

    package com.freeter.util; import java.util.UUID; /** * @author liuqi * **/public class Uuid{ public ...

  10. XGBoost 引入 - 提升树

    认识提升树 这个boosting 跟 Adaboost 不同. Adaboost 是通过上一轮的误差率来动态给定一下轮样本不同的权重来学习不同的模型. 现在的方式, 更多是基于残差 的方式来训练. 一 ...