让我解释一下我申请的目的,这样你就可以指导我最好的方法。
我们的想法是构建一个Web应用程序来远程管理我公司生产的某些特定设备。这些设备将定期连接到远程服务器以发送/接收某些数据(通过简单的套接字通信,但他们不使用Java);这些数据将存储在相应的数据库中,并可通过Web应用程序为不同的用户提供。
同样,当您通过Web界面访问时,每个客户端都能够看到他们的设备并对配置执行不同的更改。此时有两种可能的选择,这就是这篇文章的原因:
最简单但不是最佳选项:用户执行一些更改,我将这些更改保存在数据库中。当设备稍后与服务器建立通信时,它将读取这些更改并更新其配置。
理想的解决方案:用户只要通过网络界面保存更改并按下"发送"按钮,这些更改将发送到相应的设备。
如上所述,这些设备将定期向服务器打开套接字通信(假设每5分钟一次)以发送其配置。此时,为了实现理想的解决方案",我能想到的唯一选择就是不要关闭该套接字,以便我可以使用它立即将信息发送回设备。任何改变。
如果这个应用程序随着时间的推移而增长,我担心太多的开放套接字/线程会导致我的应用程序崩溃。
让我用一些我正在玩的代码来说明。我知道这远不是最终解决方案,它只是为了帮助您理解我正在寻找的东西。
首先,我在Web服务器启动期间注册套接字服务器(在本例中为Tomcat):
package org.listeners;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.sockets.KKMultiServer;
public class ApplicationListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
KKMultiServer kKMultiServer = new KKMultiServer();
Thread serverThread = new Thread(kKMultiServer);
serverThread.start();
event.getServletContext().setAttribute("PlainKKMultiServer", kKMultiServer);
}
public void contextDestroyed(ServletContextEvent event) { }
}
这是侦听新连接的主套接字服务器类:
public class KKMultiServer implements Runnable {
private Map<Long, KKMultiServerThread_v2> createdThreads = new HashMap<Long, KKMultiServerThread_v2>();
@Override
public void run() {
boolean listening = true;
try (ServerSocket serverSocket = new ServerSocket(5000)) {
while (listening) {
KKMultiServerThread_v2 newServerThread = new KKMultiServerThread_v2(serverSocket.accept(), this);
Thread myThread = new Thread(newServerThread);
myThread.start();
Long threadId = myThread.getId();
System.out.println("THREAD ID: " + threadId);
}
} catch (IOException e) {
System.err.println("Could not listen on port " + 5000);
System.exit(-1);
}
}
public Map<Long, KKMultiServerThread_v2> getCreatedThreads() {
return createdThreads;
}
}
使用每个设备(分配器)的每个请求创建的线程类来处理套接字通信:
public class KKMultiServerThread_v2 implements Runnable {
private Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
private long dispenserCode;
private KKMultiServer kKMultiServer;
public KKMultiServerThread_v2(Socket socket, KKMultiServer kKMultiServer) {
this.socket = socket;
this.kKMultiServer = kKMultiServer;
}
public void run() {
try {
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
readDataFromDispenser();
}
private void readDataFromDispenser() {
String inputLine;
try {
while ((inputLine = in.readLine()) != null) {
if (inputLine.equals("Bye")) {
break;
}
if (dispenserCode == 0) {
dispenserCode = 1111; // this code will be unique per equipment
this.kKMultiServer.getCreatedThreads().put(dispenserCode, this);
}
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendDataToDispenser(String dataToSend) {
if (!socket.isClosed() && socket.isConnected()) {
out.println(dataToSend);
} else {
this.kKMultiServer.getCreatedThreads().remove(this);
}
}
}
现在socket已经创建并且活着我可以直接从Web应用程序使用它来将消息发送回设备(在这种情况下是Struts Action)
public class HelloWorldAction extends ActionSupport {
private static final long serialVersionUID = 1L;
public String sendMessageToDispenser() throws Exception {
ServletContext context = ServletActionContext.getServletContext();
KKMultiServer kKMultiServer = (KKMultiServer) context.getAttribute("PlainKKMultiServer");
Map<Long, KKMultiServerThread_v2> currentThreads = kKMultiServer.getCreatedThreads();
Iterator<Long> it = currentThreads.keySet().iterator();
while (it.hasNext()) {
Long key = (Long) it.next();
KKMultiServerThread_v2 currentThread = currentThreads.get(key);
currentThread.sendDataToDispenser("DATA TO YOU!");
}
return SUCCESS;
}
}
您认为可以执行此解决方案吗?我的意思是,保持这些连接打开,这样我就可以在必要时访问我的设备(无需等待定期连接)。什么是最好的方法?如果您有任何其他建议,请告诉我。
非常感谢。
答案 0 :(得分:0)
在我看来,这显然取决于系统连接的设备数量。套接字并不总是发送数据,因此它对整体性能的影响很小。虽然,Socket被认为有点慢,如果你有很多数据要发送到你的设备,你应该考虑这个。
如果您想将数据从服务器发送到客户端,那么您的解决方案很少
我认为没有其他解决方案,但我可能错了。如果您的设备每隔X秒请求您的服务器,它将永远不会完全按时完成。