Implementing a simple java TCP server - java

There are two readers plugged to the internal network. They just send data to the server machine, where I want to have this java app running receiving the data. It won't be that much data. Each reader could be transmitting single strings like "1234567" to a rate as much as maybe half a dozen times per second.
Without entering into much detail about the readers, they are datalogic and both are different models, but with this in common: They are configured to transmit the data via tcp/ip to a certain ip:port.
I tested the data trasmission with this software: https://www.hw-group.com//products/hercules/index_en.html to see if I'm receiving the data properly and it does check out, it works well.
The problem comes when I run my TCP server implementation: I receive the data from one of the devices 100% of the times, while the other one is hit and miss: Sometimes the data sent over the network never makes it to my app and I don't know why.
I'm pasting the code of what I'm using: It's simple but, with my java knowledge and after digging around the internet, it's the best I came up with.
Here's the java file with the main:
package tcpserverclasstest;
public class TCPServerClassTest {
public static void main(String[] args) throws InterruptedException {
TCPServerThread myTCPServerThread = new TCPServerThread();
myTCPServerThread.start();
}
}
Here's TCPServer.java:
package tcpserverclasstest;
import java.io.IOException;
import java.net.Socket;
import java.io.*;
public class TCPServer extends Thread {
public static final int PORT_NUMBER = 4413;
protected Socket socket;
public TCPServer(Socket socket) {
this.socket = socket;
System.out.println("New client connected from " + socket.getInetAddress().getHostAddress());
start();
}
public void run() {
InputStream in = null;
try {
in = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String request;
request = br.readLine();
System.out.println("Message received:" + request);
} catch (IOException ex) {
System.out.println("Unable to get streams from client");
} finally {
try {
in.close();
socket.close();
System.out.println("Socket closed");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
And here's TCPServerThread.java:
package tcpserverclasstest;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServerThread extends Thread {
public static final int PORT_NUMBER = 4413;
protected Socket socket;
public void run(){
System.out.println("Waiting for incoming connections on port " + PORT_NUMBER);
ServerSocket server = null;
try {
server = new ServerSocket(PORT_NUMBER);
server.setReceiveBufferSize(262144);
server.setReuseAddress(true);
while (true) {
new TCPServer(server.accept());
}
} catch (IOException ex) {
System.out.println("Unable to start server.");
} finally {
try {
if (server != null)
server.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
I tried to implement the server on a thread since I want to implement this into a bigger project in the future and I don't want that app locked in the loop that is waiting for connections.
Any clues on what should I do to see why I'm not receiving some of the data? Any suggestion on a better way to achieve this?
Thanks!

first thing that comes to mind is your server only connects to one of the clients. Your TCPServerThread's run method listens for one connection and when it is made it initializes a TCPServer with this connection, meaning only one of the readers connects. Maybe after connecting to one reader you can listen for other.
Second, your TCPServer reads only one line and then closes the connection, and a line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed. So your readers should send linefeed ('\n', or '\r', or '\r\n'). If not you shouldn't use readLine, maybe read some amount of data in a while loop.
To debug your TCP connections and really be sure the data is actually coming to your server, you can use WireShark. This shows all the packets coming in your network card and you can filter based on tcp.port to see only your connections.

Related

Java chat program works on localhost, but not when hosting on Heroku

Long story short, I stole and modified some code from GeeksForGeeks to practice with sockets. Running code modified for localhost works fine on desktop, but when modifying and attempting to host on Heroku, I can't seem get a connection between the server and client. Server appears to launch and run fine on Heroku, and logs connections that I'm not even making (no idea where those are coming from). Client on the other hand seems to connect, but then doesn't do anything when I send a message. Server doesn't even log my attempted connection, so I know it probably isn't even connecting.
Server code: https://github.com/RenegadeB5/socket in /src/main/java/
Client Code:
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class Client
{
public static void main(String args[]) throws UnknownHostException, IOException
{
Scanner scn = new Scanner(System.in);
// establish the connection
Socket s = new Socket("<my app name>.herokuapp.com", 80);
// obtaining input and out streams
DataInputStream dis = new DataInputStream(s.getInputStream());
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
// sendMessage thread
Thread sendMessage = new Thread(new Runnable()
{
#Override
public void run() {
while (true) {
// read the message to deliver.
String msg = scn.nextLine();
try {
// write on the output stream
dos.writeUTF(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
// readMessage thread
Thread readMessage = new Thread(new Runnable()
{
#Override
public void run() {
while (true) {
try {
// read the message sent to this client
String msg = dis.readUTF();
System.out.println(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
sendMessage.start();
readMessage.start();
}
}
I've tried so many different combinations and solutions, and can't find any examples of this being done before. I'd like to know what I'm doing wrong so that I can move on from this headache. Thanks in advance!
Java Socket and ServerSocket use TPC, which is not supported for free by Heroku. As a result, the server will run fine, but anything being sent via TCP, including connection attempts, will not make it to your server unless they are done via http.

open multiple server socket ports for multiple clients

I am trying to open multiple ports on a server socket so that i could connect multiple clients. Each time i create a create a thread and start it (i know the overridden run method will be invoked) i open a port and listen for a client .
But the problem is that when i run the client socket project and try to connect to the port i opened in server ,it says java.net.connectException : connection refused:connect.
I also noticed a peculiar thing happenning.The output in the console window is different every time i run the "server code "
i have been working on this for the last 3 days and i have achieved nothing i guess.
note: this problem is unique for me as i have not found this particular problem on this forum any where so please be kind as i am a newbie to java and socket programming though i have been coding on c++ for quite some time now .
server socket
import java.io.*;
import java.net.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.*;
public class TryThreads extends Thread
{
private int Portnumber;
private static String inputLine;
public TryThreads(int portNumber)
{
Portnumber = portNumber;
setDaemon(true);
}
public static void main(String[] args)
{
//create three threads
Thread first = new TryThreads(63400);
Thread second = new TryThreads(63401);
first.start();
second.start();
//third.start();
System.out.println("ending main");
return;
}
public void run()
{
try
{
System.out.println("one socket port opened");
ServerSocket serverSocket = new ServerSocket(Portnumber);
System.out.println("one socket port opened");
while (true)
{
System.out.println("ending main2");
//System.out.println("one socket port opened");
Socket clientSocket = serverSocket.accept();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while((inputLine = bufferedReader.readLine()) != null)
System.out.println(inputLine);
}
}
catch(IOException e)
{
System.out.println(e);
}
}
}
client socket
import java.io.*;
import java.net.Socket;
public class client
{
private static PrintWriter printWriter;
public static void main(String[] args)
{
BufferedReader in = null;
try
{
Socket socket = new Socket("localhost",63400);
printWriter = new PrintWriter(socket.getOutputStream(),true);
printWriter.println("Hello Socket");
printWriter.println("EYYYYYAAAAAAAA!!!!");
}
catch(Exception e)
{
System.out.println(e);
}
}
}
In your TryThreads constructor, use:
setDaemon(false);
You have set your server threads to be daemon threads and they are therefore terminating as soon as main exits, so your server is stopping as soon as you start it.
See Thread.setDaemon():
The Java Virtual Machine exits when the only threads running are all daemon threads.
By the way, after the above issue is corrected, be aware that your implementation will lead to the server receiving a "connection reset" SocketException, which will break your server thread out of its loop and prevent it from accepting additional exceptions. You can fix this on the client side by doing socket.close() before you exit to ensure a graceful shutdown, but you will still want to fix it on the server side since you cannot assume that clients will be well-behaved.
Normally whenever you want to write a message using PrintWriter, you need to flush it when your done (printwriter.flush()). That makes sure the message is sent.

Bufferedreader blocks thread but adding in if(br.ready()) stops disconnect check

Im making a chat server/client. I have a BufferedReader reading my inputstream from a socket, and when it .readLine() it blocks. I added in if(BufferedReader.ready()) but that means I can no longer detect disconnected clients, as if i did add in else System.out.println("Client disconnected") then whenever the client user does not send a message for more than a couple of milliseconds it presumes the user is dissconnected.
How do I get out of this?
code:
import java.io.BufferedReader;
import java.io.InputStream;
import java.net.Socket;
public class SpeechHandler implements Runnable {
public SpeechHandler (BufferedReader r, ServerMain sm, Socket soc) {
try {
boolean connected = true;
while (connected) {
try {
String text = null;
text = r.readLine();
if (!text.equals(null)) {
sm.tellAll(text);
}
} catch (Exception e) {
System.out.println("Client " + soc.getInetAddress() + " has disconnected");
sm.removeStream(soc.getInputStream());
sm.removeStream(soc.getOutputStream());
e.printStackTrace();
connected = false;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void run () {
}
}
Found Answer The problem was not the reader blocking the thread, but the fact that all the code was written in the constructor, not the run() method, as that meant the other thread waited for the constructor to complete before moving on.
I have a BufferedReader reading my inputstream from a socket, and when it .readLine() it blocks.
Correct. That is the specified behaviour.
I added in if(BufferedReader.ready()) but that means I can no longer detect disconnected clients
Correct. There are few if any correct uses of ready(), and this isn't one of them.
then whenever the client user does not send a message for more than a couple of milliseconds it presumes the user is dissconnected.
That's a bug in your code. Don't 'presume' after 'a couple of milliseconds'.
How do I get out of this?
You are using blocking I/O. You are expected to dedicate a thread to reading from the socket, and detecting end of stream or an exception to indicate peer disconnection.

Server with multiclients via thread

I'm having a bit of trouble, now I have looked at this tutorial
http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html
This tutorial gives you a server that multiple clients can connect to, when they connect to the server they are told to go along with a knock knock job, now I understand how to transfer the data and what not, but how does the threads work?
I'm working on a networked pong game where a server will hold the positions and pass them to the clients, now I have a client connected to the server and the ball position is passed to the client, works fine, a bit jumpy but I'm sure a thread with .sleep will help. but anyways my question is, how can i get my client to become a thread? and how can I store them?
For example here is the knock knock server multiThread class
package knockKnockServer;
import java.net.*;
import java.io.*;
public class KKMultiServerThread extends Thread {
private Socket socket = null;
public KKMultiServerThread(Socket socket) {
super("KKMultiServerThread");
this.socket = socket;
}
public void run() {
try {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String inputLine, outputLine;
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
out.println(outputLine);
while ((inputLine = in.readLine()) != null) {
outputLine = kkp.processInput(inputLine);
out.println(outputLine);
if (outputLine.equals("Bye"))
break;
}
out.close();
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
And here in the server we have
package knockKnockServer;
import java.net.*;
import java.io.*;
public class MultiKKServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(-1);
}
while (listening)
new KKMultiServerThread(serverSocket.accept()).start();
serverSocket.close();
}
}
Now looking at the server it will create a new KKMultiServerThread on each connection, but how can i store them? can i make a array of KKMultiServerThread?
I tried to make an array of KKMultiServerThread
and when i try this line
multi[0] = new KKMultiServerThread(serverSocket.accept()).start();
I get this error "cannot convert void to Thread"
If anyone can shine some light on my problem it would be great.
Canvas
Update
I now have my own thread class
package Pong;
import java.net.*;
import java.io.*;
public class PongPlayerThread extends Thread
{
private Socket socket = null;
private String pongData = "";
public PongPlayerThread(Socket socket, int id)
{
super("PongPlayerThread");
this.socket = socket;
}
public void passData(String data)
{
pongData = data;
}
public void run()
{
try
{
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
while(true)
{
out.println(pongData);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
the pongData is a string that holds all the information together in a string, now if i declare a player1 at the top of my pong server like so
private static PongPlayerThread player1;
and do this line when it is listening
while(listen)
{
PongPlayerThread player1 = new PongPlayerThread(serverSocket.accept(), 0).start();
}
it gives me this error "cannot convert from void to PongPlayerThread" how do i fix this?
Your array declaration is missing the object type
KKMultiServerThread multi[0] = new KKMultiServerThread(serverSocket.accept()).start();
Why bother though? Unless the threads needs to communicate with each other, letting the threads run freely is ok. The Run() method defines the entire lifetime of the socket as far as the server is concerned. Each thread has a separate copy of the state of the game (as long as you don't use statics) and will happily communicate with the client without any extra intervention.
This is a case where the Socket/Thread library in Java is doing you a big favor, don't make it more complicated unless you have a specific need.
When ever a client connects to the server. The server will typically create a new thread specifically for that client. Here is some pseudo code:
WHILE SERVER IS RUNNING
SERVER WAITS FOR A CLIENT TO CONNECT
SERVER ACCEPTS THE CLIENT IF THERE IS ENOUGH MEMORY TO CREATE A NEW THREAD
SERVER CREATES A NEW THREAD ROUTINE FOR THE CLIENT PASSING THE CLIENT INFORMATION TO THE THREAD
SERVER CONTINUES TO LISTEN WHILE EACH THREAD IS SPECIFICALLY TAILORED FOR THE CLIENTS
REPEAT
You asked what steps are needed to reduce lag? Well for starters, set a maximum allowed connections. You do not want 5000 clients having their own thread. Unless your machine can handle all that and still run. Use UDP instead of TCP, and data compression try to minimize bandwidth don't send 50 GB of information at a time; if all you need is a couple of bytes of information to send. Try to send information of positions not as strings but in bytes. For example you can send the position X=5Y=0 as 50 and parse the first decimal digit as X and the second decimal digit as Y.
Instead of passing the client socket inside the thread routine pass a unique identifier for the client. Since Pong is two players limit the connections to two clients. 0 for Player 1 and 1 for Player 2. So
new KKMultiServerThread(clientID).start(); // clientID is of type int
Edit:
int id = 0;
while(serverIsRunning)
{
Client client = server.accept();
if (id > 2) client.Close(); // Do not accept.
Thread.New(id).Start();
id++;
}

Socket server hang when testing with ab, waiting BufferedReader.readline()

I am making a Java-based web server. But when I am testing it with ApacheBench, it sometimes stop responding.
On a Macbook Air:
ab -n 20000 -c 40 -d http://localhost:1080/
is guaranteed to timeout after 16400 or more requests were done.
On Ubuntu desktop
ab -n 20000 -c 1000 -d http://localhost:1080/
could done successfully most of the time, but sometimes stop responding after several runs.
I've identified (using Eclipse) that when the server stop responding, it is waiting for BufferedReader.readline() which I use it to read HTTP request header. But I have no idea why is it waiting.
Test code is here:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestServer {
public static void main(String[] args){
ServerSocket socket = null;
try{
socket = new ServerSocket(1080);
ExecutorService pool = Executors.newFixedThreadPool(10);
while(true){
Socket s = socket.accept();
pool.execute(new RequestHandler(s) );
}
}
catch(Exception e){
e.printStackTrace();
}
finally{
if(null!=socket){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
class RequestHandler implements Runnable{
final Socket s;
public RequestHandler(Socket s) {
this.s = s;
}
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = br.readLine();
PrintWriter pw = new PrintWriter(s.getOutputStream());
pw.print("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
pw.print(line);
pw.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
if(s!=null){
try {
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
BTW, when writing the test code, I found something else strange
If
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = br.readLine();
is replaced with
String line = "don't read the socket";
ab will fail with such message: "apr_socket_recv: Connection refused (111)Connection reset by peer (104)"
But open localhost:1080 with Firefox 4 will see the "don't read the socket" mess show up.
I wonder if this is a deliberate part of the ApacheBench test: to see how your server behaves when a connection is opened to it but then no data sent. Presumably ApacheBench is open source so you can have a look at see if it invokes some special behaviour (my bet is on it opening the socket and then not sending a request) after 16400 tries.
In any case, you probably want to make sure you set an explicit timeout on the socket in case your version of Java is defaulting to 0 (=infinite). Don't assume that every client will behave perfectly and always send you precisely the data you're expecting.
So as a general rule, you need to make sure that your web server doesn't fall over if "something unusual happens"-- networks are like that, and sometimes packets/connections will get randomly dropped and you need to deal with it. Operating systems may well impose limits on e.g. how long a connection can be open for and so your server could suddenly see the "rug pulled from beneath it's feet" by the OS. I imagine the ApacheBench test may simulate a few gremlins like this (which could even be what you're seeing in Ubuntu, though the readLine() hanging is probably a simulation of not sending a request on an open connection as I mention).

Categories

Resources