使用TCP套接字线程的Spring Boot应用程序 - 我正确地做了吗?

时间:2018-05-22 11:06:57

标签: java spring multithreading spring-boot autowired

我正在运行一个从IoT端点接收数据的Spring Boot应用程序。它是一种专有协议,因此我只使用基于this example from Oracle的标准TCP套接字实现。

目前我有一个@Component开始一个新线程:

@Component
public class TCPSocketServer {

  @Autowired
  private TCPServerRunnable sr;


  @PostConstruct
  public void init() throws IOException
  {
    sr.setSocket(new ServerSocket(43110));
    Thread server = new Thread(sr);
    server.start();
  }

  @PreDestroy
  public void clean()
  {
    // close any open sockets, resources, etc.
    sr.stop();
  }
}

和服务器逻辑,为每个连接启动一个新线程:

@Component
public class TCPServerRunnable implements Runnable {

  private ServerSocket serverSocket = null;
  private static boolean isRunning = true;
  @Autowired
  private VehicleService vehicleService = null;

  @Override
  public void run() {
    //TODO: Remove comments.
    System.out.println("TCP thread started...");
    while (isRunning) {
      System.out.println("Accepting new TCP connections...");
      try {
        new TCPServerRunnableHandler(serverSocket.accept(), vehicleService).start();
      } catch (IOException ex) {
        System.out.println("TCP socket creation failed...");
      }
      System.out.println("TCP connection established...");
    }
  }

  private static class TCPServerRunnableHandler extends Thread {

    private Socket clientSocket;
    private DataOutputStream out;
    private DataInputStream in;
    private VehicleService vehicleService;

    public TCPServerRunnableHandler(Socket socket, VehicleService vehicleService) {
      this.clientSocket = socket;
      this.vehicleService = vehicleService;
    }

    public void run() {
      try {
        out = new DataOutputStream(clientSocket.getOutputStream());
        in = new DataInputStream(clientSocket.getInputStream());

        while (isRunning)  {
          byte[] data = new byte[512];
          int packetEnd = 0, i = 0;
          while (packetEnd < 2) {
            data[i] = in.readByte();
            if (data[i] == (byte)0xC0) {
              packetEnd++;
            } else {
              if (data[i] == (byte)0xDC && i > 0 && data[i-1] == (byte)0xDB) {
                data[i-1] = (byte)0xC0;
              } else {
                i++;
              }
            }
          }
          Protocol protocol = new Protocol(vehicleService);
          data = protocol.processMessage(data, clientSocket.getInetAddress().getHostAddress(), clientSocket.getPort());

          for (int j = 0; j < data.length; j++) {
            if (data[j] == (byte) 0xC0 && j > 0) {
              out.writeByte(0xDB);
              out.writeByte(0xDC);
            } else {
              out.writeByte(data[i]);
            }
          }
          out.writeByte(0xC0);
          out.flush();
        }

        in.close();
        out.close();
        clientSocket.close();
      } catch (IOException ex) {
        System.out.println("TCP iot interface exception....");
      }
    }
  }

  void stop() {
    isRunning = false;
  }

  public void setSocket(ServerSocket socket) {
    this.serverSocket = socket;
  }
}

我遇到的问题是我不知道协议是否是使用连接到数据库的@Service vehicleService并根据收到的消息更新Vehicle字段的正确类。第二个问题是我不喜欢线程的实现。我不能直接在Protocol类中自动装配Vehicle Service,因为它没有被Spring Boot实例化。

您能否告诉我如何处理这些主题?有没有更好的方法在Spring Boot中执行上述操作?

感谢您的任何建议!!!

1 个答案:

答案 0 :(得分:0)

除了纯Java套接字外,我一直在寻找类似的方法。这是我的实现,您可能会考虑两个优点。

  1. 所有对象都在春季IOC中
  2. 线程由java.util.concurrent.Executors处理

客户

@Component
public class SocketServer {

@Autowired
private SocketServerRunnable socketServerRunnable;

@PostConstruct
public void init() throws IOException {
    try (var listener = new ServerSocket(59898)) {
        System.out.println("The server is running...");
        var pool = Executors.newFixedThreadPool(100);

        //External Loop
        while (true) {
            socketServerRunnable.setSocket(listener.accept());
            pool.execute(socketServerRunnable);
        }
    }
}

服务器

@Component
@Scope("prototype")
@Data
public class SocketServerRunnable implements Runnable {
private ServerSocket serverSocket;
private Socket socket;

@Override
public void run() {
    System.out.println("Connected: " + socket);
    try {
        DataInputStream din = new DataInputStream(socket.getInputStream());
        DataOutputStream dout = new DataOutputStream(socket.getOutputStream());
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        String str = "", str2 = "";
        while (!str.equals("stop")) {
            //gateway.route(din);
            str = din.readUTF();
            System.out.println("client says: " + str);
            str = din.readUTF();
            System.out.println("client says: " + str);
            str = din.readUTF();
            System.out.println("client says: " + str);
            str2 = br.readLine();
            dout.writeUTF(str2);
            dout.flush();
        }
        din.close();
        //socket.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}