Writing to a Serversocket Outputstream from different Java Classes with Java Delegate

Im writing a Spring Boot Server Application where multiple Clients should Connect to my TCP Server in different Threads. While starting the Application I start the Servers like this in main method of Application.java:

Runnable serverZyklisch = new ServerZyklisch();
    Runnable serverAzyklisch = new ServerAzyklisch();

    for (int i = 0; i < 4; i++) {
      new Thread(serverZyklisch).start();
      new Thread(serverAzyklisch).start();
    }
    SpringApplication.run(Application.class);

So the IP-Adress of the Clients Ill get connected are:

Connection from /10.50.12.204 (drill)
Connection from /10.50.12.172 (press)

This is my ServerAzyklisch Class:

package com.example.workflow;

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerAzyklisch implements Runnable, JavaDelegate {
    int count = 0;
    private final ServerSocket ssocket;
    static String param = StartTCPServersDelegate.parameter;
    HexToByteConverter hexToByteConverter = new HexToByteConverter();
    // 2 TCP Server starten Port 2000, Port 2001
    public ServerAzyklisch(String Pparam) throws IOException {
        ssocket = new ServerSocket(2000);
        param = Pparam;
    }

    public ServerAzyklisch() throws IOException {
        ssocket = new ServerSocket(2000);
    }

    public void run() {
        byte[] buf = new byte[1];
        InputStream in;
        OutputStream out = null;
        Socket socket;
        //Thread immer aktiv
        while(true){
            try {
                // Wartet auf Socket Verbindung
                System.out.println("Server is listening on port "+ ssocket.getLocalPort());
                socket = ssocket.accept();
                count++;
                System.out.println("Countet clients: "+count);
                socket.setSoLinger(true, 1000);
                System.out.println("Sockeport: "+socket.getLocalPort());
                System.out.println("Connection from " + socket.getInetAddress().toString());
                //Inputstream
                in = socket.getInputStream();
                //Outputstream
                out = socket.getOutputStream();
                //Datenpuffer deklarieren (anlegen)
                byte []data = new byte[132];
                            
                byte[]Pressen1hexdump110 = hexToByteConverter.hexStringToByteArray("33333333003d0064000600000004004001c9c78900010000006e0000000000000000000000000001000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"+param);
                byte[]Pressen2hexdump = hexToByteConverter.hexStringToByteArray("3333333300400065000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
                byte[]Pressen3hexdump = hexToByteConverter.hexStringToByteArray("3333333300400065001400000000004001c9c6e900010000006e000000000000000000000000000100000000001e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
             
               in.read(buf);
                while (buf[0] != -1) {

                    out.write(Pressen1hexdump110);
                    out.write(Pressen2hexdump);
                    out.write(Pressen3hexdump);
                    }
                
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void execute(DelegateExecution delegateExecution) throws IOException {
        
    }
}

Now I have following BPMN:
bohrenDannPressen.bpmn (2.8 KB)

Where I connect the Service Tasks to my Java Classes with Java Delegate:

Bohrer.java Class:

package com.example.workflow;

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Bohrer implements JavaDelegate {
    ServerSocket ssocket;
    private HexToByteConverter hexToByteConverter = new HexToByteConverter();
    byte[]Bohrer1hexdump120 = hexToByteConverter.hexStringToByteArray("33333333003d0064000600000004004001c9c78900010000007800000000000000000000000000010000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002");
    byte[]Bohrer2hexdump121 = hexToByteConverter.hexStringToByteArray("33333333003d0064000600000004004001c9c78900010000007800000000000000000000000000010000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001");
    byte[]Bohrer3hexdump122 = hexToByteConverter.hexStringToByteArray("33333333003d0064000600000004004001c9c78900010000007800000000000000000000000000010000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003");
    Socket socket;
    InputStream in;
    OutputStream out;
    @Override
    public void execute(DelegateExecution delegateExecution) throws Exception {
        System.out.println("In Execute von Bohrer");
        PostRequestDelegate postRequestDelegate = new PostRequestDelegate();
        postRequestDelegate.postBohrer();
        Bohrer bohrer = new Bohrer();
        bohrer.sendMessage(bohrer.in,bohrer.out,null);
    }

    public Bohrer() throws IOException {
        ssocket = new ServerSocket(2000);
        socket = ssocket.accept();
        //Inputstream
        in = socket.getInputStream();
        //Outputstream
        out = socket.getOutputStream();
    }

    public void sendMessage(InputStream in, OutputStream out, byte[]message) throws IOException {
        out.write(Bohrer1hexdump120);
        out.write(Bohrer2hexdump121);
        out.write(Bohrer3hexdump122);
    }
}

And my Presse.java Class:

package com.example.workflow;

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Presse implements JavaDelegate {

    ServerSocket ssocket;
    private HexToByteConverter hexToByteConverter = new HexToByteConverter();
    Socket socket;
    InputStream in;
    OutputStream out;

    byte[]Pressen1hexdump110 = hexToByteConverter.hexStringToByteArray("33333333003d0064000600000004004001c9c78900010000006e00000000000000000000000000010000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005");
    byte[]Pressen2hexdump = hexToByteConverter.hexStringToByteArray("3333333300400065000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
    byte[]Pressen3hexdump = hexToByteConverter.hexStringToByteArray("3333333300400065001400000000004001c9c6e900010000006e000000000000000000000000000100000000001e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");


    public Presse() throws IOException {
        ssocket = new ServerSocket(2000);
        socket = ssocket.accept();
        //Inputstream
        in = socket.getInputStream();
        //Outputstream
        out = socket.getOutputStream();
    }

    public void sendMessage(InputStream in, OutputStream out, byte[]message) throws IOException {
        out.write(Pressen1hexdump110);
        out.write(Pressen2hexdump);
        out.write(Pressen3hexdump);
        socket.close();
    }

    @Override
    public void execute(DelegateExecution delegateExecution) throws Exception {
        PostRequestDelegate postRequestDelegate = new PostRequestDelegate();
        postRequestDelegate.post();
    }


}

I want to achieve that if the process is at first Service Task “Bohren rechts” (Drill on right side) that I send to Client via Outputstream.write the 3 Messages I declared.
The same procedure with the Task “Pressen 5 Sekunden” in his execute-method.

But if I started the Application, the Clients are already connected to my Server. It will throw Error:
org.camunda.bpm.engine.impl.pvm.PvmException: couldn't execute activity <serviceTask id="Activity_1g6swbl" ...>: Address already in use: NET_Bind

I think this is caused by the ssocket.accept(); the second time, but I dont know how to use the connection which should be already there via my two Classes instead of in ServerAzyklisch class.

Seems the port is already in use. try to use different port.

Yes, but I think I have to go this way.
The clients/machines will connect to my TCP Server while starting. So far so good. This works.
But I want to reuse this connection, because I can send to one machine/client for example in ServerAzyklisch class, with out.write(). Now I want to send to client in the other two classes similar like in the ServerAzyklisch class. But I think socket.accept on the same port is the wrong way, but I need this Port because the clients are listening on this Port (2000). I want to outsource the “out.write” parts in my Bohrer.class and Presse.class that I can write to client back if the process reached the ServiceTask.

Address already in use: NET_Bind means that you’re trying to bind to an already occupied port.

Something is already listening at port 2000 when you start your server: possibly a prior instance of it; or possibly there is still a socket in TIME_WAIT. Try it with SOCKET_REUSEADDR, this way:

ServerSocket serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(2000));

:exclamation: Also, make sure that socket connections are closed properly.

You mean this Code in Bohrer Constructor, or ?
How can I get Inputstream and Outputstream from client socket then ?

I got this with socket = ssocket.accept();
and then in = socket.getInputStream();
out = socket.getOutputStream();

All the 3 classes you’re creating new Socket(2000), but you closed in only 1 class. When you try to create socket with same port without closing it will throw the error. You might consider it to closing socket connection at the end otherwise try to reuse the same socket connection.

Do you mean if I close the Connection on Port 2000 in right way, I can do Socket.accept() in my new Classes ?

yes. correct. And moreover it’s not issue with camunda framework. The issue is related to socket programming. The alternate approach i would suggest is REST api call rather than Socket programming (traditional).

you are right, but the machines cant understand REST Calls, so I have to use the Socket Programming for that. Can you tell me, where in ServerAzyklisch class (I think in run method) I have to close serversocket, so thats in right way closed ?