我正在java中编写一个监听特定端口的服务器。不同的客户端定期向服务器发送消息。
消息包含客户端的相应公钥。
服务器有一个公钥列表。
如果列表中没有新接收的公钥,服务器会将其添加到那里。
我已经完成了比较公钥和编写列表中不存在的公钥的部分。
多线程服务器的代码(此处服务器实际侦听两个不同的端口):
while(!isStopped()){
System.out.println("Server is working");
try {
serverSocket = ServerSocketChannel.open();
serverSocket.configureBlocking(false);
serverSocket.bind(new InetSocketAddress(serverPortRequest));
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
serverSocket = ServerSocketChannel.open();
serverSocket.configureBlocking(false);
serverSocket.bind(new InetSocketAddress(serverPortAccept));
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
while(selector.isOpen()){
selector.select();
Set<SelectionKey> readyKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = readyKeys.iterator();
while(iterator.hasNext()){
SelectionKey key = (SelectionKey) iterator.next();
if(key.isAcceptable()){
SocketChannel client = serverSocket.accept();
(new Thread(new WorkerRunnable(client,"Multithreaded Server"))).start();
}
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
在WorkerRunnable线程中,我检查客户端的公钥是否已经在服务器列表中:
if(!isPresent(userPK)) {
FileOutputStream pk;
try {
pk = new FileOutputStream("contactsPK/contact"+Server.pkCounter++);
pk.write(userPK);
pk.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
此处userPK
是一个byte
数组,用于存储从客户端发送的消息中获取的公钥。
如何定期检查(例如30秒)客户端列表中的客户端是否未向服务器发送消息?我想从服务器的存储公钥列表中删除该客户端,即其公钥。
答案 0 :(得分:2)
这是一个非常好的问题!
你几乎想要实现你想要实现的目标,你只需要小心几个陷阱!
您可以使用以下命令启动代码:
while(!isStopped()){
...
}
这是确保您始终在端口上进行侦听的一种方法,但您还要做的是为该进程创建互斥锁。你可以在这里阅读:
http://en.wikipedia.org/wiki/Mutual_exclusion
这样做可以确保在您运行此代码时没有其他进程可以访问处理器。有了这个,不幸的是,当你开始扩展你的代码并添加功能时,你会看到这个循环会阻止你解耦你的代码,确保健壮性和增加功能(我会回到这个后来!)。首先,您要做的是为您的应用程序使用Web框架,这可以使用多种不同的选项来完成。以下是两种可以帮助您做出决定的资源:
http://en.wikipedia.org/wiki/Comparison_of_web_application_frameworks#Java
我建议从Spring MVC框架开始,它是目前最通用和最广泛使用的,你可以在线获得足够的资源来帮助你入门。
一旦您选择了框架,您就会想要创建一个MVC架构Web应用程序,这里有几个资源:
http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller http://blog.codinghorror.com/understanding-model-view-controller/
您的视图不会包含太多内容,实际上它可以将公钥传递给您的后端(您的控制器和模型)。
通过上面提到的,您可以摆脱所有循环的代码并等待从端口听到ping,您可以简单地指定要在Spring MVC配置文件中侦听的端口。
现在为有趣的部分!你问:
"How do i check at regular intervals (say 30 seconds) that a client, from the list of clients, has not sent the server a message? I would like to delete that client i.e. its public key from the list of stored public keys of the server."
这可以通过你后端的两个商店实现:redis - 基于会话的密钥库,以及你风味的简单关系数据库。
您的算法可以简单地如下:
1. Every time your view forwards the information of a request to your backend, add it to your redis database, in the form <id, key>
2. Simply create a thread to run every 30 seconds to do:
2a. get the list of id's from redis
2b. perform a left outer join on table a and b, where A is your sql table of ids, and B is the list of ids from redis. A left outer join returns all the values from an inner join plus all values in the left table that do not match to the right table. Here is a resource for SQL Joins: http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
2c. The result of the join is your final answer, be sure to store this in your db.
2d. purge all keys from redis (this is a one-liner)
您可以使用ScheduledExecutorService创建一个在后端每30秒运行一次的线程,如下所示:
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
// 2a from above: (get the list of id's from redis)
// 2b from above (perform a left outer join on table a and b, where A is your sql table of ids, and B is the list of ids from redis. A left outer join returns all the values from an inner join plus all values in the left table that do not match to the right table.)
// 2c from above (The result of the join is your final answer, be sure to store this in your db)
// 2d from above (purge all keys from redis (this is a one-liner)
}
}, 0, 30, TimeUnit.SECONDS);
由于这是一项非常具体且可重复的任务,因此您还有其他一些与其相关的权衡。您可以创建一个crontab作业,该作业可以执行执行上述操作的脚本,甚至可以使用内置于许多关系数据库功能中的触发器。两者的主要缺点是,如果您选择这样做,您将失去代码可见性。
我上面也提到了关于去耦的问题。当您开始编写可扩展的代码时,耦合(http://en.wikipedia.org/wiki/Coupling_(computer_programming)是一个非常重要的概念。您希望尽可能保持代码松散耦合(http://en.wikipedia.org/wiki/Loose_coupling),因为它将进行调试和制作以OOP方式写作对你来说更容易。