I'm working on an Android application that
First, I have to connect to hardware server via TCP socket
After connected, I will have to send *99*1## to server, then server will response with "*#*1##*#*1##"
Then, I need to keep this socket alive and read incoming message
After this point, server can send me message from times to times. But, When will message sent or length of message are undetermined.
Every message will end with '##', For example, *1*1*18##, *1*0*19##, *1*1*#4*11## and else.
When client (this app) receive message, it will notify activity to update UI.
So, I create a thread subclass to do this
public class ServerThread extends Thread {
public interface OnReadListener {
public void onRead(ServerThread serverThread, String response);
}
Socket socket;
String address;
int port;
OnReadListener listener = null;
public ServerThread(String address, int port) {
this.address = address;
this.port = port;
}
#Override
public void run() {
try {
socket = new Socket(InetAddress.getByName(address), port);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
PrintWriter writer = new PrintWriter(bw, true);
writer.println("*99*1##");
writer.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while (!socket.isConnected() && !Thread.currentThread().isInterrupted()) {
line = br.readLine();
if (line != null) {
Log.i("Dev", "Line ")
if (listener != null) {
listener.onRead(this, line);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void setListener(OnReadListener listener) {
this.listener = listener;
}
}
And in the activity, I do it like this
public class MainActivity extends Activity {
ServerThread st = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
}
#Override
public void onResume() {
startMonitoring();
super.onResume();
}
#Override
public void onPause() {
stopMonitoring();
super.onPause();
}
private void startMonitoring() {
stopMonitoring();
st = new ServerThread(SERVER_IP_ADDRESS, SERVER_PORT);
st.setListener(new OnReadListener{
#Override
public void onRead(ServerThread serverThread, String response) {
runOnUiThread(new Runnable() {
#Override
public void run() {
// update UI or do something with response
}
})
}
});
st.start();
}
private void stopMonitoring() {
if (st != null) {
st.stop();
st = null;
}
}
}
After I start this activity, I found that
The message "*99*1##" has been send to server, I can see this message from server hardware.
But, I only got first line of response from server '*#*1##*#*1##'
After that, socket is still connected (stacktrace not printed) but I never got any further message from server. Listener never gets called.
I have no idea how to make this work. Any suggestion are welcome.
Some note you might need to know
I'm not quit sure that BufferReader is the right object I need for the job or not. Because when it failed to read, it will return null and the loop will keep running. I might need some object that can freeze the thread waiting for input. This object can wait for input as long as it takes since the server may send message in seconds, minutes, hours or more. Once message has received, the continue to execute the code and go to the next round of loop.
(I'm full-time iOS Dev, not really familiar with Java)
Final Edit
After I carefully check the code, I found the silly mistake I made
writer.println("*99*1##")
Basically, println will send "*99*1##" and then follow with newline. But my hardware server doesn't like that so it terminate the connection. That's why I got null from BufferReader's readLine().
After I change to
writer.print("*99*1##")
The server receive "*99*1##" and keep connection. Then, and I can loop to read response just like EJP suggest again
String line;
while ((line = br.readLine()) != null) {
if (listener != null) {
listener.onRead(this, line);
}
}
if (listener != null) {
listener.onTerminated(this);
}
while (!socket.isConnected() ...
The problem is here. The test is pointless anyway, as it will never be false, but negating it means that the controlled block will never execute. Just remove the isConnected() test.
when it failed to read, it will return null and the loop will keep running.
Because you didn't handle that case correctly. If line is null you must exit the loop and close the connection. The usual way to write that is:
String line;
while ((line = reader.readLine()) != null)
{
// ...
}
Your sleep in your loop is just literally a waste of time.
Try this
while (isRunning) {
line = br.readLine();
if (line != null) {
Log.i("Dev", "Line ")
if (listener != null) {
listener.onRead(this, line);
}
}
}
Note: isRunning is a boolean variable to control your thread life cycle. Whenever you want to stop this thread, set isRunning = false and call close() on your connection.
If you want to create a TCP server you should use ServerSocket instead Socket. Here is java document about socket but android use the same http://docs.oracle.com/javase/tutorial/networking/sockets/
Related
I have a P2P network of nodes holding records of key:value, which can pass requests to other nodes on the network when the asked node doesn't hold the desired key. The operation always returns an "OK" or an "ERROR". However, when a server thread recieving the request passes it down to all the other connected nodes by calling a method, the anwser ("OK" or "ERROR") isn't captured by the method, but by the main loop in run().
Here is the simplified code:
the run() method of the server thread class:
public void run(){
String line;
try {
while (true){
line=in.readLine();
if(line!=null){
else{
switch (line.split(" ")[0]){
case "set-value":
out.println(setValue(line.split(" ")[1]));
break;
System.out.println("default:");
System.out.println(line);
break;
}
}
}
}
} catch (IOException e) {
System.out.println("connection closed with: "+socket.getInetAddress().getHostAddress()+":"+socket.getPort()+" (server socket)");
}
}
the setvalue() method:
private String setValue(String arg) throws IOException {
String setKey = arg.split(":")[0];
String setValue = arg.split(":")[1];
if(DatabaseNode.getKey().equals(setKey)){
DatabaseNode.setValue(setValue);
System.out.println("set-value successful, current record: "+DatabaseNode.getKey()+":"+DatabaseNode.getValue());
return "OK";
} else {
System.out.println("key not on this node, searching...");
for (ServerConnect sc : DatabaseNode.getConnectToClient()) {
System.out.println("sending set-value to: "+sc);
if(sc.sendRead("set-value "+arg ).equals("OK")) {
return "OK";
}
}
for (ServerThread st : DatabaseNode.getConnectedToServer()) {
if(st != this) {
System.out.println("sending set-value to: "+st);
if(st.sendRead("set-value "+arg).equals("OK")) {
return "OK";
}
}
}
}
return "ERROR";
}
and the problematic one, sendRead(), which is supposed to send a string and wait for the anwser, but instead is ignored and anwser is captured by the main run() method
public String sendRead(String str) throws IOException {
out.println(str);
String line;
System.out.println("sent "+str+" awaiting response...");
line = in.readLine();
System.out.println("got "+line);
return line;
}
Thank you for your help
I tried identifying the threads on incoming line, and I am absolutely sure that the same thread which is supposed to read from method just starts a new loop and does nothing with sendRead().
The socket is NOT static, autoFlush on BufferedReader is enabled.
I just figured out what was wrong, the readLine() call in run() steals the next line, leaving the method hanging.
EDIT: I have corrected the mistake below in the code, by adding a line into the server code
I'm trying to write some socket code that will allow me to send data from one computer to another for a game (which for simplicity's sake, we can think of as tic-tac-toe, not much data needs to be sent, just a couple of numbers). In order to achieve this I have written two classes, Server and Client. At the moment I am testing through the localhost using port 1234, and I am only using one single instance of the program (though the same problem occurs when trying to use two instances).
Firstly here's the code, and then I can go into more depth about the problem, and what testing I've done to attempt to work out what is going wrong:
public class Server
{
private ServerSocket server;
private Socket socket;
private Client socketHandler;
private static final int DEFAULT_PORT = 1234;
public Server() { this(DEFAULT_PORT); }
public Server(int port)
{
Thread thread = new Thread()
{
public void run()
{
try
{
System.out.println("Attempting to Establish Connection");
server = new ServerSocket(port);
socket = server.accept();
socketHandler = new Client(port, socket); //THIS LINE ADDED
System.out.println("Server Online!");
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
thread.setDaemon(true);
thread.start();
}
//ADJUSTED
Client getSocketHandler()
{
return socketHandler;
}
public void kill()
{
try
{
if (socket != null) socket.close();
if (server != null) server.close();
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
socket = null;
server = null;
}
}
}
public class Client
{
public static final int DEFAULT_PORT = 1234;
public static final String DEFAULT_HOST = "localhost";
private static final String THUMP_THUMP = "thump thump";
private static final int PULSE = 1000;
private int port;
private String ip;
private Socket socket;
private BufferedReader input = null;
private PrintWriter output = null;
boolean closed = true;
String data = "";
public Client() { this(DEFAULT_PORT, DEFAULT_HOST, null); }
public Client(int port) { this(port, DEFAULT_HOST, null); }
public Client(int port, String ip) { this(port, ip, null); }
public Client(int port, Socket server) { this(port, DEFAULT_HOST, server); }
public Client(String ip) { this(DEFAULT_PORT, ip, null); }
public Client(String ip, Socket server) { this(DEFAULT_PORT, ip, server); }
public Client(Socket server) { this(DEFAULT_PORT, DEFAULT_HOST, server); }
public Client(int port, String ip, Socket server)
{
socket = server;
this.ip = ip;
this.port = port;
Thread thread = new Thread()
{
public void run()
{
try
{
initialise(server);
String line;
startHeartbeat();
while (isClosed()) {} //first it is closed, lets wait for it to open before we start waiting for it to close!
System.out.println("We are about to listen!");
while (!isClosed())
{
System.out.println("pre-read"); //this line was used to determine that the code was hanging on the next line
line = input.readLine(); //offending line
System.out.println("post-read"); //this line was used to determine when the block was lifted
if (line != null)// || line != THUMP_THUMP)
{
System.out.println(line);
data += line + "\n";
}
}
System.out.println(data);
kill();
System.out.println("Connection Closed!");
}
catch (SocketException e)
{
e.printStackTrace();
System.out.println("Server closed!");
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
thread.setDaemon(true);
thread.start();
}
private void initialise(Socket server)
{
try
{
if (server == null) socket = new Socket(ip, port);
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
}
catch (IOException e) { e.printStackTrace(); }
}
public boolean post(String text)
{
synchronized(this)
{
output.println(text);
output.flush();
return !output.checkError();
}
}
public void kill()
{
try
{
if (input != null) input.close();
if (socket != null) socket.close();
}
catch(IOException e) { e.printStackTrace(); }
finally
{
input = null;
socket = null;
}
}
public void killOutputStream()
{
try
{
if (output != null) output.close();
}
catch (Exception e) { e.printStackTrace(); }
finally
{
output = null;
}
}
//////////////////////////////////
///////// Socket Control /////////
//////////////////////////////////
synchronized boolean isClosed()
{
return closed;
}
synchronized void setClosed(boolean b)
{
closed = b;
}
//We need to make sure that the socket is still online, to ensure the reading stops when the connection closes.
void startHeartbeat()
{
Thread heartbeat = new Thread()
{
public void run()
{
while (output != null)
{
setClosed(post(THUMP_THUMP) ? false : true); //post returns true on success
synchronized(this)
{
try
{
this.wait(PULSE);
}
catch (InterruptedException e) {}
}
}
setClosed(true);
}
};
heartbeat.setDaemon(true);
heartbeat.start();
}
}
The Problem
When the client is started (after having created the server) it fails to read any data sent through (or even the heartbeat), in fact the code does not go past line = input.readLine() in the reading thread (which is from now on called the offending line), except it seems, until the server is disconnected (see below).
Here is the order of regular testing:
Server() is called and the resulting Server is stored in the serverConnection variable then
Client(serverConnection != null ? serverConnection.getSocket() : null) is called and the new Client is stored in clientConnection.
Because we can test whether it is working using the heartbeat no other data needs to be sent, and the server is terminated by calling serverConnection.kill() and then clientConnection.killOutputStream() after letting some time elapse.
and this is the result:
Attempting to Establish Connection Server Online!
We are about to listen!
Connection Closed!
where the empty line represents the non null data received over the course of the connection, ie that there is none.
I expect this:
Attempting to Establish Connection
Server Online!
We are about to listen!
thump thump
thump thump
thump thump (and so on, every second)
Connection closed!
I spent time performing different tests by commenting out or changing the code slightly with the same testing format (except for the special case, which is number 6) and made these observations:
Observations
Only when the socket is closed and the output stream is closed, does the program move past the offending line.
When the readline() method starts to process (shortly before the heartbeat cuts it off) it detects nothing in the stream, not even THUMP_THUMP.
When the socket is closed, but the output stream is not, the readline() method starts to process, only to detect nothing, heartbeat cuts it off. No SocketException even though it would be expected.
If the socket is NOT closed, and only the output stream is closed, a SocketException is triggered, suggesting the socket is closed.
I used netstat -an in command prompt, and when the server is started the port 1234 is LISTENING. When the client connects, it is still LISTENING, implying that there is no connection.
I set up some python code to connect to itself over port 1234,
however I made a mistake in the python code, and as such the server
didn't close, and was still open. So I decided to connect the java
client to the server and see what happens. I did this by running
Client(null) which is the client code for the non-host. It
resulted in the port reading ESTABLISHED, and the python server was
echoing back the "thump thump", and the java code was successfully
reading it. No hanging, it worked perfectly.
This leads me to believe that the problem lies in the server code, as the python server was able to communicate sucessfully with the Java client, but the Java client is unable to communicate with the Java server.
Before performing this testing I had been concentrating on the Client code, believing that it was at fault. All the questions I have found here with similar symptoms (see here, here and here, among others) have turned up blank for me, having written in their solutions (most were due to the output stream not flushing, or the \n ommitted, which I have not failed to do, or the solution not fixing my problem, and so having been removed in favor of the heartbeat in this case). I originally based my code off of this article.
After 4 days of trying to figure out this problem I am at a loss for what to do... What am I missing here? Why is the Server code not working as I expect it to? If anybody needs any more clarification on my code then please ask!
As an after-note, the testing code is run through a simple minimalistic GUI written in javafx (not fxml though), whether that would be a problem or not I'm sure, I would think not, due to it working with the Python server. This code is compiled in Java 8
I'm a little confused about why you think it would go any furthur than input.readLine() considering there is no handling of inputs/outputs on the server side....
Client/Server connections are like a game of tennis, as one side serves the other must receive the ball and then serve it back(maybe with different information). Your server side must handle the input it recieves from the start heartbeat method, and then send you back a response. the input.readLine() function blocks the thread until it receives data from the other end, so yes the code stops there and waits for your server to send the "tennis ball" back. In the server class you should add an input and output stream that handle the heart beat inputs and send back a string of data to the client.
Server:
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
String response = "thump thump";
while(true){
is.read();
os.write(response.getBytes());
os.flush();
}
with this example, the client should remain unchanged and just add the above code to your server.
I'm using a server socket to accept clients on the main thread, when a thread is accepted,the clients socket is given to a handler which is started in a new thread to process communications. However, before I start running my server to access clients, it connects to a second server which it must list to and be able to respond to and pass on the messages it gets to it's clients.
Hopefully this image illustrate what I mean:
The small server must be continuously listening for input from the big server, and also able to output responses.
//Default constructor
private smallServer(){}
//method to initialise and start the server
public static void StartServer(int port) throws IOException {
smallServer ss = new smallServer();
ss.bs= new bigServerClient(ss);
Thread nsc_Thread = new Thread(ss.bsc);
bsc_Thread.start();
//accepts clients and starts new thread for them
ss.ServerRun(port);
}
private void ServerRun(int port) throws IOException {
ServerSocket server = new ServerSocket(port);
server.setSoTimeout(50);
while (run) {
Socket client = null;
try {
client = server.accept();
} catch (SocketTimeoutException e) {
}
if (client != null) {
ClientHandler handler = new ClientHandler(client, this);
Thread handleThread = new Thread(handler);
handleThread.start();
}
}
if (!run) {
synchronized (ClientHandler.handlers) {
for (ClientHandler handler : ClientHandler.handlers) {
handler.terminateHandler();
}
}
System.exit(0);
}
}
public void processBigServerCommand(String toProcess) {
System.out.println("RESEAVED: " + toProcess);
}
The big server client(on the small server) then does this:
public class bigServerClient implements Runnable {
private smalsServer ss;
private PrintWriter printer;
private BufferedReader reader;
private Socket socket;
public bigServerClient(smallServer _ss) throws IOException {
ss = _ss;
socket = new Socket("Localhost", 5000);
printer = new PrintWriter(socket.getOutputStream());
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
printer.flush();
SendBigServerMessage("Starting String");
}
private void SendBigServerMessage(String toSend) {
printer.print(toSend);
printer.flush();
}
#Override
public void run() {
try {
while (ss.state()) {
String inputLine;
while ((inputLine = reader.readLine()) != null) {
ss.processBigServerCommand(inputLine);
System.out.println(inputLine);
}
}
} catch (IOException e) {
} finally {
try {
socket.close();
} catch (IOException ex) {
}
}
}
}
From what's above, can anyone see why the big server client isn't responding to the big server when a message is sent? I'm guessing it's something to do with the main thread blocking the second thread, but I'm not sure... Any help would be greatly appreciated.
You lost me in your code...
Simplify it.
Your smallServer (see class names conventions) should have persistent connection to BigServer (effectively it is BigServer client) - you can implement it in your smallServer class, it should connect (once) and open I/O to BigServer (once) and close everything once the connection is terminated.
As your smallServer will handle multiple clients and pass their requests to BigServer there is no guarantee of the order of BigServer responses - you should do something to handle that (maybe pass UUID with requests?)
Simplify your smallServer and make sure that it runs...
I have a thread that uses network port for communication. I added
cancel() method to stop the execution and close network resources (How to properly stop the Thread in Java?)
private class ServerThread extends Thread {
int portNumber;
String serverAddress = null;
public ServerThread(String serverAddress, int portNumber) {
super();
this.serverAddress = "localhost";
this.portNumber = portNumber;
}
#Override
public void run() {
ServerSocket listener;
Socket socket;
try {
listener = new ServerSocket(this.portNumber);
socket = listener.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(),
true);
while (!isInterrupted()) {
String input = in.readLine();
if (input != null) {
out.println(input);
System.out.println("Hi:" + input);
}
} // end of while loop
System.out.println("OUT"); <-- ???
socket.close(); <-- ???
listener.close(); <-- ???
} catch (IOException e) {
e.printStackTrace();
}
}
public void cancel() {
System.out.println("cancel called");
interrupt();
}
}
The issue is that when I execute the ServerThread, and send cancel() message to finish the execution, it seems like that the three lines of code never executed: System.out.println("OUT"); socket.close(); listener.close();.
It also seems like that I don't need to send cancel() message to finish the thread.
ServerThread s = new ServerThread(serverAddress, serverPortNumber);
s.start();
...
s.cancel(); // ???
What's the recommended way of closing resources used by threads?
Don't I have to close resources when thread is not used anymore? Or everything is just automatically processed?
ADDED
It seems like that the thread is killed automatically as this code just works.
while(true) {
String input = in.readLine();
if (input != null) {
System.out.println("Received:" + input);
out.println(input);
}
} // end of while loop
/* System.out.println("OUT");
socket.close();
listener.close(); */
Thread#interrupt() will not interrupt the blocking I/O call on the socket. Try setting a "stop" flag and closing the socket in the cancel() method instead, and deal with the exception and check the flag in the while loop.
InterruptibleChannels reacts on the interrupt call, but not "old fashioned" socket streams.
In Java 7 you can use the try (resource) {} catch idiom like this:
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
while ((line = reader.readLine()) != null) {
process(line);
}
} catch (IOException e) {
e.printStackTrace();
}
This will guarantee that the stream is closed properly once the try block is left. No matter what happens inside or how the try/catch terminates.
I'm trying to make a networking application, for a proof of concept project.
I need to keep the connection open, the joined clients, but the while loop I'm running never gets out of the first loop.
Code:
public class comm implements Runnable {
private Socket socket;
private String line, input;
boolean sending = true;
boolean connected = false;
private int me;
private BufferedReader br;
private PrintWriter pw;
doComms(Socket server) {
socket = server;
me = Main.connected;
}
public void run() {
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
pw = new PrintWriter(socket.getOutputStream(), true);
while (true) {
System.out.println("Waiting");
readCommand();
}
} catch (Exception ex) {
System.out.println(ex);
}
}
private void readCommand() throws Exception {
String str;
while (br.readLine() != null) {
if (!connected) {
pw.println("connect");
}
str = br.readLine();
System.out.println(str);
if (str.startsWith("!START!")) {
System.out.println("User connected");
connected = true;
String[] split = str.split("#");
Main.jTable1.getModel().setValueAt(split[1], me, 2);
Main.jTable1.getModel().setValueAt(split[2], me, 3);
Main.jTable1.getModel().setValueAt("Connected...", me, 4);
}
}
}
}
Starting that code is fine, all it does is makes a new thread for each connected users, and the client software runs fine too. what am I doing wrong?
My best guess. It never gets out of the first readCommand call because readCommand itself is in an infinite loop:
while (br.readLine() != null) {
br.readLine will block until the next line from the socket input arrives. So the only way for the loop to exit is for the remote client to disconnect.
But the while loop I'm running never gets out of the first loop.
The first loop you are referring to is:
while(true) { ... }
This will never exit because true is always true.