All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bidib.jbidibc.net.serialovertcp.NetBidibServerPlainTcpPort Maven / Gradle / Ivy

The newest version!
package org.bidib.jbidibc.net.serialovertcp;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.collections4.map.HashedMap;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NetBidibServerPlainTcpPort implements NetBidibPort {
    private static final Logger LOGGER = LoggerFactory.getLogger(NetBidibServerPlainTcpPort.class);

    private final NetMessageHandler messageReceiver;

    private AtomicBoolean runEnabled = new AtomicBoolean();

    private ServerSocket serverSocket;

    private final ScheduledExecutorService acceptWorker = Executors.newScheduledThreadPool(1);

    private Map clientMap = MapUtils.synchronizedMap(new HashedMap<>());

    /**
     * Creates a new instance of {@code NetBidibServerTcpPort}.
     * 
     * @param portNumber
     *            the port number
     * @param bindAddress
     *            the (optional) bind address
     * @param messageReceiver
     *            the message receiver
     * @throws IOException
     */
    public NetBidibServerPlainTcpPort(int portNumber, InetAddress bindAddress, NetMessageHandler messageReceiver)
        throws IOException {

        this.messageReceiver = messageReceiver;

        if (bindAddress != null) {
            this.serverSocket = new ServerSocket(portNumber, 50, bindAddress);
            LOGGER.info("Created TCP server socket for bind address: {},  port number: {}", bindAddress, portNumber);
        }
        else {
            this.serverSocket = new ServerSocket(portNumber);
            LOGGER.info("Created TCP server socket on port number: {}", portNumber);
        }

    }

    @Override
    public void run() {
        LOGGER.info("Start the TCP socket.");
        runEnabled.set(true);

        // add a task to the worker to let the node process the send queue
        acceptWorker.submit(new Runnable() {

            @Override
            public void run() {
                // we must receive from multiple clients
                while (runEnabled.get()) {
                    try {
                        LOGGER.info("Wait for client to connect.");

                        Socket socket = serverSocket.accept();
                        LOGGER.info("The client connection was accepted byte the server socket, socket: {}", socket);

                        InetAddress remoteAddress = socket.getInetAddress();
                        if (remoteAddress != null) {
                            String remoteIpAddress = remoteAddress.getHostAddress();

                            try {
                                messageReceiver.acceptClient(remoteIpAddress);

                                registerClient(socket);

                                NetBidibPlainTcpServerSocketHandler handler =
                                    new NetBidibPlainTcpServerSocketHandler(socket, messageReceiver,
                                        clientSocket -> unregisterClient(clientSocket));
                                handler.start();
                            }
                            catch (Exception e) {
                                LOGGER.warn("Client was not accepted.", e);

                                unregisterClient(socket);

                                try {
                                    socket.close();
                                }
                                catch (Exception e1) {
                                    LOGGER.warn("Close socket of unaccepted client.", e1);
                                }
                            }
                        }
                        else {
                            LOGGER.warn("No remote address available for socket.");
                            try {
                                socket.close();
                            }
                            catch (Exception e) {
                                LOGGER.warn("Close socket without remote address available failed.", e);
                            }
                        }
                    }
                    catch (IOException ex) {

                        if (runEnabled.get()) {
                            LOGGER.error("Start listen on server socket failed.", ex);
                            runEnabled.set(false);
                        }
                        else {
                            LOGGER.info("The server socket listener is stopped.");
                        }

                        return;
                    }
                }

                LOGGER.info("The server socket acceptor has finished.");
            }
        });

        LOGGER.info("Start server port has passed.");
    }

    @Override
    public void stop() {
        LOGGER.info("Stop the TCP packet receiver, serverSocket: {}", serverSocket);

        runEnabled.set(false);

        if (serverSocket != null) {
            LOGGER.info("Close the server socket.");
            try {
                serverSocket.close();
            }
            catch (IOException ex) {
                LOGGER.warn("Close serverSocket failed.", ex);
            }

            try {
                LOGGER.info("Shutdown acceptWorker.");
                acceptWorker.shutdown();
                acceptWorker.awaitTermination(2000, TimeUnit.MILLISECONDS);
            }
            catch (Exception ex) {
                LOGGER.warn("Wait for shutdown of acceptWorker failed.", ex);
            }
            serverSocket = null;
        }

        // cleanup the clientmap
        synchronized (clientMap) {
            clientMap.clear();
        }
    }

    private void registerClient(final Socket socket) {
        LOGGER.info("Register client: {}", socket);
        if (socket == null) {
            throw new IllegalArgumentException("Mandatory socket is not available.");
        }
        synchronized (clientMap) {
            clientMap.put(socket.getPort(), socket);
        }
    }

    private void unregisterClient(final Socket socket) {
        LOGGER.info("Unregister client: {}", socket);
        if (socket == null) {
            throw new IllegalArgumentException("Mandatory socket is not available.");
        }
        synchronized (clientMap) {
            clientMap.remove(socket.getPort(), socket);
        }
    }

    @Override
    public void send(byte[] sendData, InetAddress address, int portNumber) throws IOException {
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Send data, port: {}, bytes: {}", portNumber, ByteUtils.bytesToHex(sendData));
        }

        final Collection connectedClients;
        synchronized (clientMap) {
            connectedClients = Collections.unmodifiableCollection(clientMap.values());
        }

        for (Socket socket : connectedClients) {

            if (socket != null) {
                LOGGER.info("Send data to socket: {}", socket, ByteUtils.bytesToHex(sendData));
                socket.getOutputStream().write(sendData);
                socket.getOutputStream().flush();
            }
            else {
                LOGGER
                    .warn("Send data is discarded because no socket registered for port: {}, address: {}", portNumber,
                        address);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy