基于C/S的网盘设计(JAVA)
由于有其他的工作,网盘做了一部分不得不放手了,
我希望有时间的其他朋友可以继续工作,虽然网络上有很多现成的网盘代码,不过还是希望自己能做一个,并借鉴一些优秀的思想来实现,下面说下实现过程,有些部分需要改进
一、数据库的设计,目前只涉及到用户表,当然还有其他的,你可以根据需要来增加
#用户表
create table m_user(
id int primary key auto_increment,
name varchar(32) not null unique,
password char(32) not null,
`gender` enum('男','女') NOT NULL DEFAULT '男',
phone varchar(20),
email varchar(50) not null,
reg_date char(16) not null,
reg_ip varchar(15) not null,
last_login_date char(16),
last_login_ip varchar(15)
);
二、数据源的设置,我这里使用c3p0数据源,当然你可以使用dbcp或者其他的
配置c3p0-config.xml文件就可以了,网络上有详细的配置项,或者在我源码里面下载,在最后公布下载地址
在这里我写一个简单的JdbcUtil,当然还可以编写一些复杂的操作,工作不允许我继续往下写了,你可以集成一些操作,就像hibernate那样
public class JdbcUtil {
/** * 数据库连接管理器
*/
// private static Logger log = Logger.getLogger(JdbcUtil.class);
/*初始化数据库连接池*/
private static DataSource dataSource = new ComboPooledDataSource();
/*获取数据源*/
public DataSource getDataSource(){
return dataSource;
}
/*获取连接*/
public static Connection getConnection() throws SQLException{
return dataSource.getConnection();
}
/*释放连接*/
public static void free(ResultSet rs,PreparedStatement ps,Connection conn){
if(null != rs){
try {
rs.close();
} catch (SQLException e) {}
}
if(null != ps){
try {
ps.close();
} catch (SQLException e) {}
}
if(null != conn){
try {
conn.close();
} catch (SQLException e) {}
}
}
public static void free(PreparedStatement ps,Connection conn){
if(null != ps){
try {
ps.close();
} catch (SQLException e) {}
}
if(null != conn){
try {
conn.close();
} catch (SQLException e) {}
}
}
}
三、我这里先说说服务端
1.socket线程池
池的作用想必大家都知道,循环利用资源,我这里的这个池只是简单的池,没有时间再完成一个复杂的工作了
cn.mike.server.ServerThread是一个负责处理用户请求的线程,我们要创建一批这样的线程,并由cn.mike.server.ServerThreadPool管理,代码如下:
public class ServerThreadPool {
/** * 服务端线程池
*/
private final static Logger log = Logger.getLogger(ServerThreadPool.class);
//线程组
public static LinkedList<ServerThread> threadPool = new LinkedList<ServerThread>();
private static int maxPoolSize;//最大连接数
private static int minPoolSize;//最小连接数
private static int initialPoolSize;//初始化连接数
private static int maxIdleTime;//连接的最大空闲时间,单位:秒
private static int acquireIncrement;//在当前连接数耗尽的时候,一次获取的新的连接数
static int maxWaitUserTime;//线程等待用户操作的最大时间,到达最大时间未传送数据,则进行线程释放
public ServerThreadPool(){
initProperties();
initThreadPool();
}
/* * 初始化配置
*/
public void initProperties(){
System.out.println("正在启动线程池...");
System.out.println("正在加载线程池配置文件...");
Properties pro = new Properties();
HashMap<String, String> propertiesMap = new HashMap<String, String>();
try {
pro.load(ServerThreadPool.class.getClassLoader().getResourceAsStream(ServerThreadPoolConfig.PROPS_FILE_RSRC_PATH));
propertiesMap.put(ServerThreadPoolConfig.MAX_POOL_SIZE, pro.getProperty(ServerThreadPoolConfig.MAX_POOL_SIZE));
propertiesMap.put(ServerThreadPoolConfig.MIN_POOL_SIZE, pro.getProperty(ServerThreadPoolConfig.MIN_POOL_SIZE));
propertiesMap.put(ServerThreadPoolConfig.INITIAL_POOL_SIZE, pro.getProperty(ServerThreadPoolConfig.INITIAL_POOL_SIZE));
propertiesMap.put(ServerThreadPoolConfig.MAX_IDLE_TIME, pro.getProperty(ServerThreadPoolConfig.MAX_IDLE_TIME));
propertiesMap.put(ServerThreadPoolConfig.ACQUIRE_INCREMENT, pro.getProperty(ServerThreadPoolConfig.ACQUIRE_INCREMENT));
propertiesMap.put(ServerThreadPoolConfig.MAX_WAIT_USER_TIME, pro.getProperty(ServerThreadPoolConfig.MAX_WAIT_USER_TIME));
if(null != propertiesMap.get(ServerThreadPoolConfig.MAX_POOL_SIZE)){
ServerThreadPool.maxPoolSize = Integer.parseInt(propertiesMap.get(ServerThreadPoolConfig.MAX_POOL_SIZE));
}else{
ServerThreadPool.maxPoolSize = 100;
}
if(null != propertiesMap.get(ServerThreadPoolConfig.MIN_POOL_SIZE)){
ServerThreadPool.minPoolSize = Integer.parseInt(propertiesMap.get(ServerThreadPoolConfig.MIN_POOL_SIZE));
}else{
ServerThreadPool.minPoolSize = 5;
}
if(null != propertiesMap.get(ServerThreadPoolConfig.INITIAL_POOL_SIZE)){
ServerThreadPool.initialPoolSize = Integer.parseInt(propertiesMap.get(ServerThreadPoolConfig.INITIAL_POOL_SIZE));
}else{
ServerThreadPool.initialPoolSize = 5;
}
if(null != propertiesMap.get(ServerThreadPoolConfig.MAX_IDLE_TIME)){
ServerThreadPool.maxIdleTime = Integer.parseInt(propertiesMap.get(ServerThreadPoolConfig.MAX_IDLE_TIME));
}else{
ServerThreadPool.maxIdleTime = 10;
}
if(null != propertiesMap.get(ServerThreadPoolConfig.ACQUIRE_INCREMENT)){
ServerThreadPool.acquireIncrement = Integer.parseInt(propertiesMap.get(ServerThreadPoolConfig.ACQUIRE_INCREMENT));
}else{
ServerThreadPool.acquireIncrement = 1;
}
if(null != propertiesMap.get(ServerThreadPoolConfig.MAX_WAIT_USER_TIME)){
ServerThreadPool.maxWaitUserTime = Integer.parseInt(propertiesMap.get(ServerThreadPoolConfig.MAX_WAIT_USER_TIME));
}else{
ServerThreadPool.maxWaitUserTime = 60000;
}
} catch (Exception e) {
log.error("线程池配置文件加载出错,请确保文件threadPool.properties存在,并正确配置!");
System.exit(1);
}
System.out.println("线程池配置加载成功,配置信息如下:");
System.out.println("#################################");
System.out.println("最大连接数:"+ServerThreadPool.maxPoolSize);
System.out.println("最小连接数:"+ServerThreadPool.minPoolSize);
System.out.println("初始化连接数:"+ServerThreadPool.initialPoolSize);
System.out.println("连接的最大空闲时间:"+ServerThreadPool.maxIdleTime+" 秒");
System.out.println("在当前连接数耗尽的时候,一次获取的新的连接数:"+ServerThreadPool.acquireIncrement);
System.out.println("线程等待用户操作的最大时间:"+ServerThreadPool.maxWaitUserTime+" 毫秒");
System.out.println("#################################");
}
/* * 初始化服务线程
*/
public void initThreadPool(){
for(int i=0;i<ServerThreadPool.initialPoolSize;i++){
ServerThread st = new ServerThread();
st.start();
threadPool.add(st);
}
}
/* * 线程池动态调整器
*/
public void poolAdjust(){
}
}
一些配置规范我把它放在cn.mike.server.ServerThreadPoolConfig里
public class ServerThreadPoolConfig {
/* * 线程池配置
*/
//配置文件路径
public final static String PROPS_FILE_RSRC_PATH = "threadPool.properties";
//最大连接数
public final static String MAX_POOL_SIZE = "maxPoolSize";
//最小连接数
public final static String MIN_POOL_SIZE = "minPoolSize";
//初始化连接数
public final static String INITIAL_POOL_SIZE= "initialPoolSize";
//连接的最大空闲时间,单位:秒
public final static String MAX_IDLE_TIME = "maxIdleTime";
//在当前连接数耗尽的时候,一次获取的新的连接数
public final static String ACQUIRE_INCREMENT = "acquireIncrement";
//线程等待用户操作的最大时间,到达最大时间未传送数据,则进行线程释放
public final static String MAX_WAIT_USER_TIME = "maxWaitUserTime";
}
threadPool.properties文件用于配置线程池的一些选项,我这里的设置可能不够完整,你可以根据需要增加
还有一个重要问题,这里需要开启一个线程来管理线程池里线程的数量,实现动态调整,这工作我并没完成,希望你能把它完成
cn.mike.server.Server是一个用于接收用户请求的分配器,处理一些初始化工作
public class Server {
/** * 25米 网盘 服务端
*/
private final static Logger log = Logger.getLogger(Server.class);
private int listenPort = 8594;//监听端口
private static ServerSocket ss;
static LinkedList<Socket> taskQueue = new LinkedList<Socket>();//任务队列
public static Map<String,Session> sessionMap = new HashMap<String,Session>();
/*初始化线程池*/ ServerThreadPool stp = new ServerThreadPool();
/*数据库连接工具*/
public JdbcUtil jdbcUtil = new JdbcUtil();
private int maxWaitUserTime = ServerThreadPool.maxWaitUserTime;//最大等待操作时间
public static void main(String[] args) {
System.out.println("正在启动服务器...");
Server server = new Server();
new TaskHandle().start();
server.init();
}
public void init(){
// 初始化数据库连接池
System.out.println("正在初始化数据库连接池...");
try {
System.out.println("#################################");
JdbcUtil.getConnection().close();
System.out.println("#################################");
System.out.println("数据库连接池创建成功!");
} catch (SQLException e1) {
log.error("数据库连接池创建失败!");
System.exit(1);
}
/*开启监听服务*/
try {
ss = new ServerSocket(listenPort);
System.out.println("服务器启动成功,正在监听端口:"+listenPort);
while(true){
Socket socket = ss.accept();
socket.setSoTimeout(maxWaitUserTime);//设置最大连接时长
System.out.println("发现客户端连接,IP:"+socket.getRemoteSocketAddress());
process(socket);//转入线程池处理
}
} catch (IOException e) {
System.out.println("服务器启动失败,请确保端口:"+listenPort+"不被其他程序占用!");
}
}
/* * 服务线程处理客户端请求
*/
public void process(Socket socket){
if(ServerThreadPool.threadPool.size()>0){//如果池中还有服务线程
ServerThreadPool.threadPool.removeFirst().startWork(socket);
}
else if(taskQueue.size()<1000){//若没有,并且队列长度小于1000,则加入任务队列
taskQueue.add(socket);
}
else{
try {
socket.close();
} catch (IOException e) {
log.error("关闭客户端socket失败!");
}
}
}
}
/* *开启定时器,处理任务队列,每隔 500 毫秒查看有没有空闲连接
*/
class TaskHandle extends Thread{
static LinkedList<Socket> taskQueue = Server.taskQueue;
public TaskHandle(){
System.out.println("队列任务处理器开启..");
}
public void run() {
try {
while(true){
Thread.sleep(500);
if(taskQueue.size()>0 && ServerThreadPool.threadPool.size()>0){//如果池中还有服务线程,则处理任务队列
ServerThreadPool.threadPool.removeFirst().startWork(Server.taskQueue.removeFirst());
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
可能有些东西读者不是很明白,这需要对socket编程熟悉点,当然我的设计也有些问题,希望读者能提改进意见,有时间就修改
本文地址:https://blog.gengchao.cn/post-130.html
未标注转载均为本站远程,转载请注明文章出处:
发表评论