We created a server client relation between java (eclipse on windows/server) and android app (android studio/client). The communication seems fine, but sometimes the connecting is horrably slow, up to the point where the app and and server don't respond anymore. Yet, no real error is given and there is no pattern to when the connection goes well or when it is slow.
We looked for answers here at stack, but we could only find answers regarding the output and input streams. However, once the connection (serverSocket.accept()) is made, the program runs fine and the streams are created super fast. Thus we think the problem lies with the server side creation of sockets. The program only has to handle a maximum of 30 clients, and the only communication exists of strings (so no enormous data transfers).
Note: when one connection acceptation is slow, the next upcomming requests from clients have to wait. When it's their turn they are again randomely fast or slowly accepted by the server. All connections are made on port 8080.
The code of our server and client are given below, does anybody know why the connection is (at some random times) so slow?
SERVER:
public void run() {
keepGoing = true;
try {
serverSocket = new ServerSocket(port);
while (keepGoing) {
display("Server waiting for Clients on port " + port + ".");
Socket socket = serverSocket.accept(); //<---our problem
if (!keepGoing) break;
ClientThread t = new ClientThread(socket, this); //<---program doesnt reach this code when it is slow. One client thread exists for each connection.
}catch (IOException e) {
String msg = sdf.format(new Date())
+ " Exception on new ServerSocket: " + e + "\n";
display(msg);
}
}
CLIENT THREAD CODE: (not reached if slow)
public ClientThread(Socket socket, Server s) {
this.server = s;
this.socket = socket;
System.out.println("Thread trying to create Object Input/Output Streams");
try {
// make streams
sOutput = new ObjectOutputStream(socket.getOutputStream());
sInput = new ObjectInputStream(socket.getInputStream());
// read user account info
String input = (String) sInput.readObject();
String[] accountInfo = input.split(";");
username = accountInfo[0];
password = accountInfo[1];
} "catch all problems"
}
CLIENT (android)
Thread connect = new Thread(new Runnable() {
#Override
public void run()
{
try
{
socket = new Socket(ip.getText().toString(), portNr);
sOutput = new ObjectOutputStream(socket.getOutputStream());
sInput = new ObjectInputStream(socket.getInputStream());
}
catch (UnknownHostException e ){
e.printStackTrace();
} catch(IOException e ){
e.printStackTrace();
}
"sending account information"
}
});
connect.start();
try {
connect.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Thanks so much!
You should make the streams in the ClientThread in the run() method, before you start looping. Not in the constructor. Otherwise you are doing I/O in the accept thread, which slows it down.
I have no idea why you're creating a thread in the client only to join it immediately.
You should extract your main server loop (while(keepGoing)...) into a run method and make the server implement the Runnabel interface. Then create a new Thread and start it.
Example:
public class Server implements Runnable{
private Thread thread;
public Server(){
thread = new Thread(this);
thread.start(); //I would create start() and stop() methods but for simplicity I just use thread.start()
}
#Override
public void run(){
//while....
}
}
I hope you get what I want to say, otherwise just comment and I will upgrade my example ;)
Turns out we had a router issue. When connecting all tablets and computer to a local hotspot it ran super smooth! Tanks everyone for the help :D
EDIT: Try a BufferedStreamReader mentioned here: Java socket performance bottleneck: where?
Instead of:
sOutput = new ObjectOutputStream(socket.getOutputStream());
Use:
sOutput = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
and flush it with:
sOutput.flush();
Same goes for the InputStream, use BufferedInputStream.
Related
I am running a server that enables multiple socket connections.
i am trying to shut down the thread when the client side terminated the connection.
this is the code for the client thread:
class ClientThread implements Runnable {
Socket threadSocket;
private boolean chk = false, stop = false, sendchk = false, running = true;
DataOutputStream out = null;
//This constructor will be passed the socket
public ClientThread(Socket socket){
threadSocket = socket;
}
public void run()
{
System.out.println("New connection at " + new Date() + "\n");
try {
DataInputStream in = new DataInputStream (threadSocket.getInputStream());
out = new DataOutputStream (threadSocket.getOutputStream());
while (running){
// read input from client
int ln = in.available();
byte [] bytes = new byte [ln];
in.read(bytes);
String msg = new String(bytes);
// parse in going message
messageParsing(msg);
// respond to client
response();
/////////////////////////////
////// this is the part that i thought would help me close the thread
////////////////////////////
if (threadSocket.isInputShutdown()){
running = false;
}
}
}
catch (IOException ex) {System.out.println(ex);}
finally {
try {
threadSocket.close();
System.out.println("Connection closed due to unauthorized entry.\n");
} catch (IOException ex) {System.out.println(ex);}
}
}}
However, the if statement does not do the trick. The thread is still running and tries to send/read data from the socket.
How can make it work? what am i missing?
any help would be appreciated. thank you.
isInputShutdown() tells you whether you have shutdown the input of this socket. It doesn't have anything to do with the peer.
Your problem is that you are ignoring the result of the read() method. If it returns -1, the peer has closed the connection.
NB Your use of available() is also incorrect. Just read into a fixed sized buffer.
You can greatly simplify your code.
I created class SocketListener to receive data through TCP protocol. My start method looks like this:
public void start() throws IOException {
LOGGER.log(Level.INFO, "SOCKET LISTENER STARTED PORT: " + port);
serverSocket = new ServerSocket(port);
while (true) {
FrameParser fp;
try {
socket = serverSocket.accept();
fp = new FrameParser(socket);
Thread thread = new Thread(fp);
thread.start();
} catch (Exception e) {
resetConnection();
}
}
}
Writing this code I based on example from oracle website (http://www.oracle.com/technetwork/java/socket-140484.html#server). When I placed line with serverSocket.accept() inside loop some of the packets was not received by ServerSocket. I am sure that this TCP packets was received on my network interface bacause I checked it later using Wireshark. I have no idea what causes that problem so I tried different things and I noticed that more packets was received when I change my code like this:
public void start() throws IOException {
LOGGER.log(Level.INFO, "SOCKET LISTENER STARTED PORT: " + port);
serverSocket = new ServerSocket(port);
socket = serverSocket.accept();
while (true) {
FrameParser fp;
try {
fp = new FrameParser(socket);
Thread thread = new Thread(fp);
thread.start();
} catch (Exception e) {
resetConnection();
}
}
}
I made this modification using trial and error method and unfortunately after this change my application started receive more data than I filtered in Wireshark (for example in Wireshark I saw 10 packets but my application created hundreds of new threads and it finished with out of memory error).
What can be a reason that in a first case not all of TCP packets reached to socket?
I'm trying to implement a simple server(java application) and client(android app), where the client sends a string about 10 times a second. Everything works fine for a minute or so, after which the server stops receiving messages from the client. Relevant code below.
ClientThread.java
public class ClientThread implements Runnable{
static Socket socket;
static String message = "";
InetAddress serverAddr;
BufferedOutputStream bos;
public ClientThread(String message){
ClientThread.message = message;
}
#Override
public void run() {
try{
serverAddr = InetAddress.getByName(SERVER_IP);
if(socket != null && socket.isConnected())socket.close();
socket = new Socket(serverAddr, SERVER_PORT);
bos = new BufferedOutputStream (socket.getOutputStream());
OutputStreamWriter osw = new OutputStreamWriter(bos, "US-ASCII");
osw.write(message);
osw.flush();
socket.shutdownOutput();
socket.close();
}catch (Exception e) {
}
}
}
ServerThread.java
public class ServerThread extends Thread{
private ServerSocket serverSocket;
static String clientSentence;
public ServerThread(int port) throws IOException, AWTException{
serverSocket = new ServerSocket(port);
}
public void run() {
while(true){
try{
Socket server = serverSocket.accept();
BufferedReader d = new BufferedReader(new InputStreamReader(server.getInputStream()));
clientSentence = d.readLine();
System.out.println(clientSentence);
server.close();
}catch(IOException e){
e.printStackTrace();
break;
}
}
}
}
ClientThread.java is called about 10 times a second using:
Thread clientThread = new Thread(new ClientThread(message));
clientThread.start();
ServerThread.java is initialized and started using:
t = new ServerThread(8888);
t.start();
Any thoughts on why this would freeze after running for a bit? The only way to fix it is to restart the server, after which the same problem happens again after a minute. I spent a lot of time researching this issue but was unable to find a solution.
EDIT: I figured out the server freezes at the clientSentence = d.readLine(); part. Any idea why?
60 connection per second, one minute running: 3600 connections per minute.
Closing a socket doesn't release immediately the associated file descriptor. You may run out of resource at OS layer.
Try to run netstat on server side to see the active, pending and closed connections.
You may read this post on SU.
Your thread never exits and you keep creating new ones. So you run out of something: thread space, sockets, FDs, ...
This is all wrong. Either your thread should loop or you should create a new one. Not both.
Also:
You should use a single connection, not a new one per message.
You are reading lines but to sending them, unless the data already contains a newline, which it shouldn't.
EDIT: The code below throws no exception but has no output and hangs. It should output "Test message". In main(), we start a thread that's given a server socket listening on a random port. The main thread the tries to connect and communicate with the ServerSocket on that same random port, but is apparently failing. Why?
public class IntraProcSockTest {
private static int port;
private class Listener extends Thread {
public Listener() {
}
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(0);
port = serverSocket.getLocalPort();
Socket socket = serverSocket.accept();
BufferedReader in;
String fromClient;
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
while ((fromClient = in.readLine()) != null) {
System.out.println("From client: " + fromClient);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public IntraProcSockTest() {
new Listener().start();
}
public static void main(String[] args) {
new IntraProcSockTest();
try {
Thread.sleep(5000);
Socket socket = new Socket("localhost", port);
PrintWriter socketOut = new PrintWriter(socket.getOutputStream());
socketOut.println("Test message");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
A process can connect to a socket created by itself, there is no problem. Show us the code that throws an exception and/or more details about the exception.
First of all, be careful not to specify a local port for the client socket (the one connecting to the other which is listening). Let the OS choose a random port. Remember that any socket is identified by four elements (remote host, local host, remote port, local port), if you bind both the server socket and the client socket on the same local port, let it be 4498, both sockets are defined as follows: (localhost, localhost, 4498, 4498) and this doesn't work. I suspect this might be your problem.
To avoid such problems, client sockets are often bound to a random port, chosen by the OS. Show us your code, expecially the part in which the client sockets gets created and connects to the server socket.
And about IPC, it is not always bad to use sockets as an inter-process or even intra-process communication technique. The performance is worse, obviously, and you might loose some code readability, but your software will be easily portable to a network (distributed) application. It's up to your plans, it's not like IPC sockets == bad.
To create a Socket connection in one thread you can.
ServerSocket ss = new ServerSocket(0); // open a random free port.
Socket c = new Socket(ss.getInetAddress(), ss.getLocalPort());
Socket s = ss.accept();
ss.close();
final byte[] bytes = "Hello World!".getBytes();
final OutputStream out = c.getOutputStream();
out.write(bytes.length);
out.write(bytes);
final DataInputStream in = new DataInputStream(s.getInputStream());
int len = in.read();
final byte[] b = new byte[len];
in.readFully(b);
System.out.println(new String(b));
c.close();
s.close();
If all you want is IPC within a Process, a socket is not the fastest or simplest way to go. Try using a Pipe (NIO) or PipeInput/OutputStream (IO). Its faster and simpler.
Pipe pipe = Pipe.open();
SinkChannel sink = pipe.sink();
SourceChannel source = pipe.source();
or
PipedOutputStream output = new PipedOutputStream();
PipedInputStream input = new PipedOutputStream(output);
BTW: You can connect a client and server Socket in the same thread, however
Using an Exchanger is 10x faster, and using a ring buffer is faster again.
If you want convenience, using an ExecutorService is the best way to deleagte work to a background pool of threads. This can still perform millions of tasks per second.
I am currently developing a client-server application and I have this problem: I want to create a different class instance depending on what the connected socket sends, but it only creates the first instance then it stucks. Here is some piece of code:
Socket clientSocket = null;
ServerSocket server = null;
String buff = null;
transfer tr = null;
colectieClienti clienti = new colectieClienti();
And:
while (true) {
try {
clientSocket = server.accept();
buff = (new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))).readLine();
if (buff.equals("client")) {
(colectieClienti.useri[colectieClienti.nrUseri++] = new clientThread(clientSocket, stmt)).start();
} else {
tr = new transfer(clientSocket);
tr.start();
}
} catch (IOException ex) {
System.out.println(ex);
}
}
I have to mention that clientThread is a class that extends Thread and communicates with a GUI, and transfer is a class that only send some files from client to server. The logic is something like this: In the GUI the user connects to the server, so it is created a new instance of clientThread and after this, when the user press a button it creates a new socket (on the client side and send a message to the server, something like "I want to create a new instance of transfer class, which is done by the buff) and receive the data. But it only creates the clientThread instance and then it stucks. Can anyone help me?
LE: This is the constructor of clientThread
public clientThread(Socket socket, Statement statement) {
comunicare = socket;
try {
oStream = comunicare.getOutputStream();
is = new BufferedReader(new InputStreamReader(comunicare.getInputStream()));
os = new PrintStream(oStream);
} catch (IOException ex) {
System.out.println(ex);
}
this.statement = statement;
}
This is only a guess, but are you sending a line terminator from the client? BufferedReader.readLine() reads until it gets a \n, \r, or a \r\n, so if the client is not writing that, the server will just wait.
First and foremost: avoid extending the thread class and opt out for implementing a runnable.
But it only creates the clientThread instance and then it stucks. Can anyone help me?
Then show us what you do when you create the clientThread, showing us what you do on the server (alone) is not enough for us to tell you what you're doing wrong.