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

org.eclipse.basyx.components.netcomm.TCPServer Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (C) 2021 the Eclipse BaSyx Authors
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 * SPDX-License-Identifier: MIT
 ******************************************************************************/
package org.eclipse.basyx.components.netcomm;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;

/**
 * Implements an NIO TCP server
 * 
 * This server supports both blocking and non-blocking operation. It manages a
 * single communication stream to a client. Communication messages consist of a
 * 32 Bit value that describes message length (bytes), followed by message
 * length bytes with payload.
 * 
 * @author kuhn
 *
 */
public class TCPServer extends TCPCommunicator implements Runnable {

	/**
	 * Port number
	 */
	protected int port = -1;

	/**
	 * Implements non-blocking semantics
	 */
	protected boolean isBlocking = true;

	/**
	 * Server socket
	 */
	protected ServerSocketChannel serverSocket = null;

	/**
	 * Create a connection server on given server port
	 */
	public TCPServer(int portNo) {
		// Store port number
		port = portNo;

		// Catch communication errors
		try {
			// Resolve address of this host
			InetAddress hostIPAddress = InetAddress.getByName("localhost");

			// Server socket channel
			serverSocket = ServerSocketChannel.open();
			serverSocket.configureBlocking(true);
			serverSocket.socket().bind(new InetSocketAddress(hostIPAddress, port));
		} catch (IOException e) {
			// Output exception
			e.printStackTrace();
		}
	}

	/**
	 * Make socket non blocking
	 */
	public void makeNonBlocking() {
		// Set my own blocking flag
		isBlocking = false;

		// Change server socket
		try {
			serverSocket.configureBlocking(false);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Add server socket (the one that receives 'accept' notifications) to given
	 * selector
	 * 
	 * @return The selector, same as input parameter
	 */
	public Selector addServerSocket(Selector selector) {
		// Register 'accept' event
		try {
			serverSocket.register(selector, SelectionKey.OP_ACCEPT);
		} catch (IOException e) {
			e.printStackTrace();
		}

		// Return selector
		return selector;
	}

	/**
	 * Accept an incoming connection
	 */
	public void acceptIncomingConnection() throws IOException {
		// Only accept connection if no connection is waiting
		if (!((communicationToClient == null) || (!communicationToClient.isConnected())))
			return;

		// Try to accept connection. Return communication socket if successful
		communicationToClient = serverSocket.accept();

		// Make communication nonblocking if blocking flag is not set
		if (!isBlocking)
			communicationToClient.configureBlocking(false);
	}

	/**
	 * Close server communication
	 */
	public void closeServer() {
		try {
			serverSocket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Server main loop (for non-blocking communication)
	 */
	@Override
	public void run() {
		// Check if we are still using blocking communication
		if (!isBlocking)
			throw new RuntimeException("TCP Server communication thread may only be used on blocking sockets.");

		// Wait for a connection
		while (true) {
			// Exception handling
			try {
				// Wait for new connection if necessary
				while (((communicationToClient == null) || (!communicationToClient.isConnected())))
					acceptIncomingConnection();

				// Stop if server channel is closed
				if (!serverSocket.isOpen())
					break;

				// Read data
				byte[] message = readMessage();

				// Notify listeners
				if (message != null)
					notifyListeners(message);
			} catch (ClosedChannelException e) {
				// Server socket has been closed
				return;
			} catch (IOException e) {
				// Print exception, continue
				e.printStackTrace();
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy