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.
Related
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.
This question already exists:
how to close a thread out of multiple instantiations
Closed 6 years ago.
I am making a skype like program. I have an "accept" thread and multiple User threads for each call. I store the accept thread in an arraylist every time a call is started. What I need to do is when there is less than two people in the call is interrupt the accept thread that goes with the user thread that send the command. To do this when an accept thread is created I log the index number and pass it on to all of the user threads so when it needs to send the interrupt command it just gets the thread from the arraylist using the index number. But when I send it nothing happens. Could someone tell me why this is? Thank you in advance!!!
Accept Thread
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class accept extends Thread { // Chat and Voice Server User Accept
private ServerSocket TextChat;
private Socket sText;
private int TextPort;
private int index;
boolean running = true;
accept(int ChatPort) {
TextPort = ChatPort;
chat.threads.add(this);
index = chat.threads.indexOf(Thread.currentThread());
try {
TextChat = new ServerSocket(ChatPort);
} catch (IOException e) {
System.out.println("Cant create server on port "+ ChatPort);
try {
TextChat.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
public void run() {
while(running == true) {
try {
sText = TextChat.accept();
System.out.println(sText+" Joined the chat");
new TextChat(sText, TextPort, index).start();
} catch (IOException e) {
System.out.println("Server on port "+TextChat+" Can't Accept");
try {
TextChat.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
System.out.println("Server on port "+TextChat+" Is Shutting Down");
try {
TextChat.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
public void setRunning(boolean run) {
running = run;
}
}
User Thread
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;
public class TextChat extends Thread {
private ObjectOutputStream out;
private ObjectInputStream in;
private Socket s;
private String msg;
private Boolean running = true;
private int port;
private String name;
private int threadIndex;
TextChat(Socket sText, int TextPort, int index) {
s = sText;
port = TextPort;
threadIndex = index;
try {
out = new ObjectOutputStream(s.getOutputStream());
if(port <= 65511) {
chat.users1.add(out);
}else {
chat.users2.add(out);
}
in = new ObjectInputStream(s.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while(running == true) {
try {
msg = in.readObject().toString();
String[] part = msg.split("/");
if(part[0].equals("MYNAME")) {
name = part[1];
System.out.println("NAME ADDED "+name);
}
if(!msg.equals(null)) {
if(port <= 65511) {
for(ObjectOutputStream o : chat.users1) {
o.writeObject(name+": "+msg);
}
}else {
for(ObjectOutputStream o : chat.users2) {
o.writeObject(name+": "+msg);
}
}
}
} catch (ClassNotFoundException | IOException e) {
System.out.println(name+" Disconneted from chat");
if(port <= 65511) {
chat.users1.remove(out);
}else {
chat.users2.remove(out);
}
if(chat.users1.size() < 2) {
System.out.println("Chat server on port "+port+" is shutting down due to not enough people in call");
chat.threads.get(threadIndex).running = false;
running = false;
}
}
}
}
}
When you interrupt a thread, all it does is set a flag. This flag is monitored by some operations, but unless you are using one of these operations, nothing happens.
If you have a thread which is blocked on IO, the most effective why to unblock the thread is to close() the stream or socket to kill it. I would also set a flag e.g. boolean closed so you can detect that any IOException thrown was the cause of you closing the socket, rather than an error.
EDIT: Some suggestions.
always uses TitleCase for class names.
avoid mutable static fields wherever possible. In this case, I don't believe you need any.
always pass shared state, and make sure it's thread safe is used from multiple threads.
Don't extend Thread rather implement a Runnable and wrap it with a Thread
You only need one server port in this cases, unless you are implementing this as a peer-to-peer service, but that doesn't appear to be the case.
no need to write verbose expressions like while (running == true) when while (running) will do.
if you have a boolean running which is shared between threads make sure it is volatile.
DON'T catch an Exception and pretend it didn't happen. You are better off throws IOException on the constructor instead of creating a dead object.
Wrap each client in an object, and only register this object, not the thread which runs the object. As you have noted, holding the Thread isn't very useful.
Don't use a wrapper like Boolean when you don't expect a null value. Use a boolean which can't be null instead.
I suggest using flags which are false by default. Instead of running used closed. This makes it easier to know what the default/normal value of the variable is.
don't hard code ports like this in code, you should pass a flag or an id to say how it should behave.
Only use Object Stream for passing general objects. For passing text you can use a Writer/Reader or Data Stream which is simpler.
You don't need to check for null for a value which cannot be null e.g. msg.equals(null) can''t every return true.
Use the spell checker in your IDE Disconneted should be Disconnected
I wouldn't disconnect when you have 1 as someone might be about to join.
I wrote a client which basically just open a socket and send content over the connection. ( the content follows the Http protocol)
The problem I'm facing regards to the question - how and when should i close the connection.
The issue is that the connection sometime closes too early ("FIN" is sent to the server before the server answered).
in this case the server's answer is lost.
I tried to use Thread.sleep before closing the connection but nothing seems to affect the time between the content is sent and the "FIN" message is sent. (viewed in Wireshark)
The answer sometimes arrive and sometimes not ( race condition).
How can i delay the "FIN" message so i won't miss the server's response?
i added the relevant class. The relevant function is sendContentOverSocket
public class SocketClient {
private String hostName;
private int portNumber;
private Socket ConnectionSocket;
public void init(String hostName, int portNumber){
this.hostName = hostName;
this.portNumber = portNumber;
this.ConnectionSocket=createSocketConnection();
}
private Socket createSocketConnection() {
Socket socket = null;
try {
socket = new Socket(this.hostName, this.portNumber);
return socket;
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return socket;
}
public void sendContentOverSocket(String content) {
try {
PrintWriter out = new PrintWriter(
ConnectionSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(
ConnectionSocket.getInputStream()));
out.print(content);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.close();
in.close();
ConnectionSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
TCP works with a concept called a half close.
When you close the socket that is an indication that you are not going to send anymore.
In your explanation I see "FIN is sent to the server before the server answered", if you are the client, that would mean that you have performed a close on the socket.
If you expect a result from a server within a certain time frame you need some kind of timing mechanism, possibly making use of select in combination with a timeout.
If the server closes his end of the connection, you detect this by receiving bytes in receive. Usually this means that you have to close the socket too.
So in conclusion there is 3 reasons for you to close the socket :
the server closes his end of the socket basically saying i am not going to send anymore
you have waited for a while and you are tired of waiting and decide to close the socket yourself.
any other error conditions but usually they all appear like receiving 0 bytes or a negative number.
You should close the connection after you've read the response, of course. Difficult to see the mystery here. No sleeps. If you don't read the response (a) you can't know whether the request succeeded or failed, and (b) the server is liable into encounter an exception as well.
Your code is poor quality. All those methods should propagate exceptions instead of catching them internally and returning null.
In case of Java 7, since all three classes, i.e. Socket, PrintWriter, BufferedReader, implement AutoCloseable and based on the fact, that you want to close socket right after you invoke sendContentOverSocket(String content) try to use the following code:
public class SocketClient {
private String hostName;
private int portNumber;
public void init(String hostName, int portNumber) {
this.hostName = hostName;
this.portNumber = portNumber;
}
public void sendContentOverSocket(String content) {
try (Socket socket = new Socket(this.hostName, this.portNumber);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
out.print(content);
} catch(IOException e) {
//Appropriate exception handler
}
}
}
In this case Java will close all resources properly by itself.
If you use Java 6 or earlier try to use try-finally block instead:
solved.
i now understand how it works.
what i was missing in the client is the attempt to read from the input Stream.
When you try to read
while ((inputFromServer = in.readLine()) != null)
the client waits for input. The only thing that will break this loop is the server closing the connection.
after that happens you can safely close the connection on the client side. No need to delay the FIN and such...
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++;
}
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).