Need help understanding TCP Channels - java

I have a machine running that sends out status information over TCP to an IP address and port you set on the machine. If I use the command line for the machine on that IP address and run "nc -l " I get the status data from the machine. I am trying to build a Java Spring application to ingest this but all the Java TCP tutorials talk about setting channel names and subscribing to channels? Are channels something that are built on top of TCP and my machine just isn't using channels or is there some default channel listened on when you run the command line "nc -l " command? Please Help I'm very confused
EDIT 1: Adding first attempt code that I can't get to integrate with the Spring application nor can I get the data to store in Spring JPA
public class EchoMultiServer {
private ServerSocket serverSocket;
public void start(int port) {
try {
serverSocket = new ServerSocket(port);
while (true)
new EchoClientHandler(serverSocket.accept()).start();
} catch (IOException e) {
e.printStackTrace();
} finally {
stop();
}
}
public void stop() {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static class EchoClientHandler extends Thread {
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
#Autowired
PowerStationService powerStationService;
//this service connects to the repository to store the data
public EchoClientHandler(Socket socket) {
this.clientSocket = socket;
}
public JSONObject mapJsonInput(String incomingText){
try{
JSONObject json = new JSONObject(incomingText);
return json;
} catch (JSONException e){
System.out.println("JSONException " + e);
return null;
}
}
public JSONObject run() {
try {
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
StringBuilder textBuilder = new StringBuilder();
int c = 0;
int leftCaratCount=0;
int rightCaratCount=0;
while ((c = in.read()) != -1) {
char character = (char) c;
textBuilder.append(character);
if (character == '{') {
leftCaratCount++;
} else if (character == '}') {
rightCaratCount++;
if (rightCaratCount == leftCaratCount) {
System.out.println(textBuilder);
JSONObject registrationJson = mapJsonInput(textBuilder.toString());
System.out.println("we got em");
powerStationService.save(new PowerStation(registrationJson.get("D").toString(), registrationJson.get("G").toString(), Integer.parseInt(registrationJson.get("Y").toString()), Integer.parseInt(registrationJson.get("S").toString()), registrationJson.get("C").toString(), registrationJson.get("Z").toString(), registrationJson.get("V").toString()));
out.println("000250{\"A\":\"45514\",\"C\":\""+registrationJson.get("Y")+"\",\"E\":\"30,5\",\"G\":\""+registrationJson.get("G")+"\",\"H\":\"0\",\"K\":\"1\",\"M\":\"123456\",\"N\":\"" + System.currentTimeMillis() + "\",\"O\":\"13371\",\"P\":\"" + clientSocket.getLocalAddress().getHostAddress() + "\",\"S\":\"60000\",\"U\":\"\",\"V\":\"\",\"W\":\"https://admin.chargenow.top/cdb-socket-api/v1/socketserver/common\",\"X\":\"0\",\"Y\":\"FJC\",\"Z\":\"\"}");
in.close();
out.close();
clientSocket.close();
}
}
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
public static void main(String[] args) {
EchoMultiServer server = new EchoMultiServer();
server.start(13370);
}
}
EDIT 2: Additionally I attempted to use the example from the Spring Examples Github to see if it could receive messages on the port I tried. I'm able to use NetCat to see the ServerOut messages but the application isn't receiving responses back
#SpringBootApplication
#EnableConfigurationProperties(SampleProperties.class)
public class TcpAsyncBiDirectionalApplication {
public static void main(String[] args) {
SpringApplication.run(TcpAsyncBiDirectionalApplication.class, args);
}
}
#Configuration
class ServerPeer {
private final Set<String> clients = ConcurrentHashMap.newKeySet();
#Bean
public AbstractServerConnectionFactory server(SampleProperties properties) {
return Tcp.netServer(properties.getServerPort()).get();
}
#Bean
public IntegrationFlow serverIn(AbstractServerConnectionFactory server) {
return IntegrationFlows.from(Tcp.inboundAdapter(server))
.transform(Transformers.objectToString())
.log(msg -> "received by server: " + msg.getPayload())
.get();
}
#Bean
public IntegrationFlow serverOut(AbstractServerConnectionFactory server) {
return IntegrationFlows.fromSupplier(() -> "seed", e -> e.poller(Pollers.fixedDelay(5000)))
.split(this.clients, "iterator")
.enrichHeaders(h -> h.headerExpression(IpHeaders.CONNECTION_ID, "payload"))
.transform(p -> "sent by server Hello from server")
.handle(Tcp.outboundAdapter(server))
.get();
}
#EventListener
public void open(TcpConnectionOpenEvent event) {
if (event.getConnectionFactoryName().equals("server")) {
this.clients.add(event.getConnectionId());
}
}
#EventListener
public void close(TcpConnectionCloseEvent event) {
this.clients.remove(event.getConnectionId());
}
}
enter code here
enter code here

TCP/IP is just one of those protocols implemented as channel adapters in Spring Integration.
See more info in the theory: https://www.enterpriseintegrationpatterns.com/ChannelAdapter.html
And here is a list of all the supported protocols in Spring Integration:
https://docs.spring.io/spring-integration/docs/current/reference/html/endpoint-summary.html#spring-integration-endpoints
What those tutorials are talking about is a messaging channel internal to your application logic. It has nothing to do with external protocol, like yours TCP/IP. You just need to understand for your self if your application is going to be client for that IP host/port or it is going to be a server opening respective socket:
https://docs.spring.io/spring-integration/docs/current/reference/html/ip.html#ip

Related

How to make a server redirect a client to another server?

So I am working on socket programming project, where the client connects first to an authentication server and once the login is successful the client is then connected to the game server.
I created a basic code and hardcoded the username/password for now, but will be using a database later.
the problem I am facing is that I do not know how to transfer the client from authentication server to game server once login is successful
here is my loginServer thead that handle the login part.
public class LoginServerThread extends Thread {
private Socket socket;
public LoginServerThread(Socket socket){
this.socket = socket;
}
#Override
public void run(){
try{
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("Client Connected");
PrintWriter output = new PrintWriter(socket.getOutputStream(),true);
String echoString;
boolean unlock = false;
while (!unlock){
output.println("USERNAME: ");
echoString = input.readLine();
if(echoString.equals("exit")){
break;
} else if (echoString.equals("username")){
for(int i = 0; i < 3;){
output.println("PASSWORD: ");
echoString = input.readLine();{
if(echoString.equals("password")){
output.println("Login Successful");
unlock = true;
break;
}else{
i++;
}
}
}
}
}
}catch (IOException e){
e.printStackTrace();
}finally {
try {
socket.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
Assume authentication and game server deploy in one jvm.When login success don't close the socket,but tranfer the socket to GameServerThread:
LoginServer just check authentication:
public class LoginServer {
private static final Logger log = LoggerFactory.getLogger(LoginServer.class);
public static void main(String[] args) throws Exception {
ServerSocket loginServer = new ServerSocket();
SocketAddress serverSocketAddress = new InetSocketAddress("localhost", 5230);
loginServer.bind(serverSocketAddress);
for (; ; ) {
Socket socket = loginServer.accept();
if (loginCHeck(socket)) {
// transfer to game server thread to process
log.info("socket check begin create thread to process");
new GameServerThread(socket).run();
} else {
// authentication failed process
}
}
}
public static boolean loginCHeck(Socket socket) {
// check authentication
return true;
}
}
public class GameServerThread extends Thread {
private Socket socket;
public GameServerThread(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
// do your really want to do
}
}
This method has the following shortcoming:
One socket need one thread to process,when have two many client the server's thread may run out. In order to overcome this,you can use Java NIO API to do the same work.

How to listen to port 80 by using Java Socket

I have a server whose port 80 is for occupied by HTTP transactions. I wanted to see the traffic in that port and I tried to use a socket program to listen to that port.
public Server(int serverPort) throws IOException {
super(serverPort);
try {
while (true) {
Socket socket = accept();
new ServerThread(socket);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
close();
}
}
// inner-class ServerThread
class ServerThread extends Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
// Ready to conversation
public ServerThread(Socket s) throws IOException {
this.socket = s;
in = new BufferedReader(new InputStreamReader(socket
.getInputStream(), "UTF-8"));
out = new PrintWriter(socket.getOutputStream(), true);
start();
}
// Execute conversation
public void run() {
try {
// Communicate with client until "bye " received.
while (true) {
String line = in.readLine();
if (line == null || "".equals(line.trim())) {
break;
}
System.out.println("Received message: " + line);
out.println(line);
out.flush();
}
out.close();
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
new Server(80);
}
However, when I run that java application, it showed a BindException: Address already in use.
So what should I do to my code and make it listen to port 80, or are there any other ways to listen to that port in Java?
If I understand you correctly you are trying to sniff the packets that are being passed to your server. If that is the case there are some answers in this post.
What Server are you running it on?
it all depends on the type of server you're working on. Tomcat for example has the type of port it's running off of in the Server.xml file.
In Windows you can run your program by administrator. In Linux using root user.

Kryonet Client immediately disconnecting from server

I am currently in the process of writing an app which has the phone connect to a server.
Both client and server are using the Kryonet framework.
The problem ist the following :
When the server is running and I then start up the client, the client immediately disconnects from the server but the Programm itself keeps running so it is only possible that the client Thread died for whatever reason.
I am using kryonet-2.21 on both server and client.
I tried my code on Android aswell as on pc.
I also tried to troubleshoot everything I could and tried everything I found searching for my problem.
The Client code :
public class LogicHandler extends Thread {
private Client client;
public LogicHandler() {
}
public Client getClient() {
return client;
}
public void run() {
client = new Client(33554432, 33554432);
new Thread(client).start();
try {
getClient().connect(5000, "localhost", 54555, 54777);
} catch (IOException e) {
e.printStackTrace();
}
Packets.register(getClient());
getClient().addListener(new Listener() {
public void received(Connection connection, Object object) {
System.out.println("received " + object);
if (object instanceof ConnectionResponse) {
}
if (object instanceof ScheduleResponse) {
}
}
public void disconnected(Connection connection) {
}
});
getClient().sendTCP(new ConnectionRequest());
}
public static void main(String[] args) {
new LogicHandler().start();
while(true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait");
}
}
}
The Server code :
public class ServerLogicHandler {
private Server server;
private List<Client> clients;
private List<Connection> connections;
public ServerLogicHandler() {
System.out.println("Server is starting!");
server = new Server(33554432, 33554432);
server.start();
try {
server.bind(54555, 54777);
} catch (Exception e) {
server.stop();
System.out.println("Port belegt. Server wird gestoppt!");
System.exit(0);
}
Packets.register(server);
clients = new ArrayList<Client>();
connections = new ArrayList<Connection>();
server.addListener(new Listener() {
public void received(Connection connection, Object object) {
System.out.println("got packet");
if (object instanceof ConnectionRequest) {
System.out.println("size " + connection.sendTCP(new ScheduleResponse()));
}
}
public void disconnected(Connection connection) {
System.out.println("Disco " + connection.getID());
}
public void connected(Connection connection) {
System.out.println(connection.getRemoteAddressTCP().getPort() + " "
+ connection.getRemoteAddressTCP().getAddress());
}
});
System.out.println("Server started!");
}
public Server getServer() {
return server;
}
public static void main(String... args) {
new ServerLogicHandler();
}
}
The client doesn't output anything apart from the 'wait' every second. This means that either the server didn't send any packet or the client closed already. My guess is that the latter happened because the server outputs the following :
Server is starting!
Server started!
54408 /127.0.0.1
Disco 1
When I start a new client the last 2 lines would just repeat e.g. '54890 /127.0.0.1
Disco 2
'
From this I guess that the client closes for whatever reason before even sending any packets. None of my Google searches brang up any success.

Java the best way of waiting & getting data from your client

I started learning networking with the main networking package in JDK, it's pretty simple and easy after a few examples. But now I am interested into making multi-client applications like a chat system.
My structure idea so far is like this:
Connection handler class, which handles incoming connections, and holds the list of clients.
If new connection was found, create a new client object, start it's thread (Client object will implement runnable, so it will start it's own looping service, it will loop for new packets received), and add it to the list.
I create a new thread for each client instead of looping through all clients because the reading from client process stops the whole execution and will wait for the client to send data, which is kinda annoys me and this is my issue there.
I have created a simple console app that receives messages from the client, but now I want to detect disconnections. I read that bufferedReader .read() method returns -1 if user is not connected, so I thought I could loop and do that every number of seconds to every client, but the thing is, the client must send a packet in order to .read() it, so let's say if you do .read() it will wait & stop the whole thread until packet is received, (I think).
This is my current code which gets messages from client:
public boolean isConnected() {
try {
this.in.read();
this.lastCheck = System.currentTimeMillis();
return true;
} catch (IOException e) {
if (!inConnection()) {
System.out.println("User disconnected");
try {
this.destruct();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
return false;
}
private boolean inConnection() {
return System.currentTimeMillis() - lastCheck < this.maxTime;
}
public void startClientService() throws IOException {
while(!this.session.isClosed()) {
if (System.currentTimeMillis() - this.checkTime > 600) {
System.out.println(System.currentTimeMillis() - this.checkTime);
if (this.isConnected()) {
int packetType = this.dataIn.readInt();
packets.getPacket(packetType);
}
}
}
}
public void destruct() throws IOException {
this.session.close();
this.connection.removeClient(this);
System.out.println("Session killed");
}
Basically what happens here, I am sending a integer packed from the client, I might have many things to do so therefore I can set many unique packet ID's, so if I want to receive and process a chat message, the packet id is 216, the client sends a int 216, server reads the packet, enters the switch loop of all packet ids and detects if its really 216, if yes it gets the instance of the packed class that handles messages & gets the bytes of the received message like this:
public class Chat implements Packet {
#Override
public void processPacket(Session c) {
String message = readMessage(c);
System.out.println("Message: " + message);
}
private String readMessage(Session c) {
byte[] data = c.readBytes();
String message = null;
try {
message = new String(data, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return message;
}
}
And this is how I read bytes:
public byte[] readBytes() {
int len;
byte[] data = null;
try {
len = this.dataIn.readInt();
data = new byte[len];
if (len > 0) {
this.dataIn.readFully(data);
}
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
Okay my problem:
after adding the is disconnected detection, when I send my message, nothing happens. This is probably due to the .read() it stops and is waiting for a response. BUT if I write a message again, I will get the message in server.
This is my temporary, ugly client:
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1", 43594);
Scanner r = new Scanner(System.in);
PrintWriter out = new PrintWriter(socket.getOutputStream());
String input;
while(true) {
input = r.next();
if (input != null) {
sendMessage(input, out);
}
}
}
public static void sendMessage(String message, PrintWriter out) {
byte[] encoded = encode(message);
out.write(0);
out.println(encoded + "\n");
out.flush();
}
public static byte[] encode(String s) {
return DatatypeConverter.parseBase64Binary(s);
}
public static String decode(byte[] s) {
return DatatypeConverter.printBase64Binary(s);
}
}
My question is: What is a better way of reading data from client without making the application wait for it and actually loop everytime? OR maybe should I have a new thread for checking if user is online so it's 2 threads per 1 client?
If someone needs my session object (client object):
public class Session extends Thread implements Runnable {
private Socket session;
private Client client;
private PrintWriter out;
private BufferedReader in;
private PacketHandler packets;
private DataInputStream dataIn;
private ConnectionHandler connection;
private final int checkTime = 1600;
private final int maxTime = 22000;
private long lastCheck;
public Session(Socket session) {
this.session = session;
this.client = new Client(this);
try {
this.setStream();
} catch (IOException e) {
e.printStackTrace();
}
this.packets = new PacketHandler(this);
System.out.println("[New session created]: " + session.getRemoteSocketAddress());
}
public void setConnectionHandler(ConnectionHandler c) {
this.connection = c;
}
public void run() {
try {
this.startClientService();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setStream() throws IOException {
this.out = new PrintWriter(this.session.getOutputStream());
this.in = new BufferedReader(new InputStreamReader(this.session.getInputStream()));
this.dataIn = new DataInputStream(this.session.getInputStream());
}
public Client getClient() {
return this.client;
}
public byte[] readBytes() {
int len;
byte[] data = null;
try {
len = this.dataIn.readInt();
data = new byte[len];
if (len > 0) {
this.dataIn.readFully(data);
}
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
public String readMessage() {
try {
return this.in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public boolean isConnected() {
try {
this.in.read();
this.lastCheck = System.currentTimeMillis();
return true;
} catch (IOException e) {
if (!inConnection()) {
System.out.println("User disconnected");
try {
this.destruct();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
return false;
}
private boolean inConnection() {
return System.currentTimeMillis() - lastCheck < this.maxTime;
}
public void startClientService() throws IOException {
while(!this.session.isClosed()) {
if (System.currentTimeMillis() - this.checkTime > 600) {
System.out.println(System.currentTimeMillis() - this.checkTime);
if (this.isConnected()) {
int packetType = this.dataIn.readInt();
packets.getPacket(packetType);
}
}
}
}
public void destruct() throws IOException {
this.session.close();
this.connection.removeClient(this);
System.out.println("Session killed");
}
}
Thanks!
While I don't have time to look over all the code, here are two things that could help you out.
1) Use a defined message header. Define X number of bytes of each message that the client will send to the server. Use these bytes to define how long the message will be, and what type of message it is. The server knows the length and layout of this header, and uses it to process the message in a particular way. Example could be a header of one byte. A value of 1 could be a I'm connected message. 2 could be I'm about to disconnect. 3 could be I'm currently away, and 4 could be an incoming chat message.
2) There are 2 ways you can handle the input. First is to use blocking IO, and create a separate thread to receive messages from each client. I believe this is what you are currently doing. The second is to use non-blocking IO, and have a separate thread iterate over the open sockets and do a read. Non-blocking will check if there is data to read, but if there is not, the thread will continue executing.

Infinite loop when deploying OSGI bundle with network server

I'm trying to implement OSGI bundle with network server which uses network sockets.
This is the complete source code: http://www.2shared.com/file/RMXby331/CB_27.html
This is the Activator:
package org.DX_57.osgi.CB_27.impl;
import java.util.Properties;
import org.DX_57.osgi.CB_27.api.CBridge;
import org.DX_57.osgi.CB_27.impl.EchoServer;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
public class CBridgeApp implements BundleActivator {
public void start(BundleContext bc) throws Exception {
ServiceRegistration registerService = bc.registerService(CBridge.class.getName(), new CBridgeImpl(), new Properties());
EchoServer();
}
public void stop(BundleContext bc) throws Exception {
boolean ungetService = bc.ungetService(bc.getServiceReference(CBridge.class.getName()));
}
private void EchoServer() {
EchoServer method = new EchoServer();
}
}
This is the source code if the Java Network server:
package org.DX_57.osgi.CB_27.impl;
import java.net.*;
import java.io.*;
public class EchoServer
{
ServerSocket m_ServerSocket;
public EchoServer()
{
try
{
// Create the server socket.
m_ServerSocket = new ServerSocket(12111);
}
catch(IOException ioe)
{
System.out.println("Could not create server socket at 12111. Quitting.");
System.exit(-1);
}
System.out.println("Listening for clients on 12111...");
// Successfully created Server Socket. Now wait for connections.
int id = 0;
while(true)
{
try
{
// Accept incoming connections.
Socket clientSocket = m_ServerSocket.accept();
// accept() will block until a client connects to the server.
// If execution reaches this point, then it means that a client
// socket has been accepted.
// For each client, we will start a service thread to
// service the client requests. This is to demonstrate a
// multithreaded server, although not required for such a
// trivial application. Starting a thread also lets our
// EchoServer accept multiple connections simultaneously.
// Start a service thread
ClientServiceThread cliThread = new ClientServiceThread(clientSocket, id++);
cliThread.start();
}
catch(IOException ioe)
{
System.out.println("Exception encountered on accept. Ignoring. Stack Trace :");
ioe.printStackTrace();
}
}
}
public static void main (String[] args)
{
new EchoServer();
}
class ClientServiceThread extends Thread
{
Socket m_clientSocket;
int m_clientID = -1;
boolean m_bRunThread = true;
ClientServiceThread(Socket s, int clientID)
{
m_clientSocket = s;
m_clientID = clientID;
}
public void run()
{
// Obtain the input stream and the output stream for the socket
// A good practice is to encapsulate them with a BufferedReader
// and a PrintWriter as shown below.
BufferedReader in = null;
PrintWriter out = null;
// Print out details of this connection
System.out.println("Accepted Client : ID - " + m_clientID + " : Address - " +
m_clientSocket.getInetAddress().getHostName());
try
{
in = new BufferedReader(new InputStreamReader(m_clientSocket.getInputStream()));
out = new PrintWriter(new OutputStreamWriter(m_clientSocket.getOutputStream()));
// At this point, we can read for input and reply with appropriate output.
// Run in a loop until m_bRunThread is set to false
while(m_bRunThread)
{
// read incoming stream
String clientCommand = in.readLine();
System.out.println("Client Says :" + clientCommand);
if(clientCommand.equalsIgnoreCase("quit"))
{
// Special command. Quit this thread
m_bRunThread = false;
System.out.print("Stopping client thread for client : " + m_clientID);
}
else
{
// Echo it back to the client.
out.println(clientCommand);
out.flush();
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
// Clean up
try
{
in.close();
out.close();
m_clientSocket.close();
System.out.println("...Stopped");
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}
}
}
}
When I try to deploy the bundle on Glassfish server the application server hangs but I can connect to the java network server using the java client. It seems that there is a infinite loop. I need help to fix the code.
Best wishes
Your bundle activator start method never returns, because you're calling constructor of your service with infinite loop. A good practice is to return as fast as possible from bundle activators.
Here is an idea how to rewrite your code:
public class EchoServer {
private volatile boolean started;
public void start() {
new Thread(new Runnable() {
#Override
public void run() {
started = true;
try {
m_ServerSocket = new ServerSocket(12111);
} catch(IOException ioe) {
System.out.println("Could not create server socket at 12111. Quitting.");
System.exit(-1);
}
System.out.println("Listening for clients on 12111...");
// Successfully created Server Socket. Now wait for connections.
int id = 0;
while (started) {
try {
Socket clientSocket = m_ServerSocket.accept();
ClientServiceThread cliThread = new ClientServiceThread(clientSocket, id++);
cliThread.start();
} catch(IOException ioe) {
System.out.println("Exception encountered on accept. Ignoring. Stack Trace :");
ioe.printStackTrace();
}
}
}
}).start();
}
public void stop() {
started = false;
}
}
Activator
public class CBridgeApp implements BundleActivator {
private EchoServer method;
public void start(BundleContext bc) throws Exception {
...
method = new EchoServer();
method.start();
}
public void stop(BundleContext bc) throws Exception {
...
method.stop();
}
}

Categories