I can not add TCP/IP Server to the service, when closing (minimizing) the application, the server does not accept data.
How to make the data transmitted continuously?
public int onStartCommand(Intent intent, int flags, int startId) {
myServer = new Server();
myServer.start();
return Service.START_STICKY;
}
Server
private class Server extends Thread {
private Socket clientSocket;
private ServerSocket server;
private BufferedReader in;
private BufferedWriter out;
private String LOG_TAG;
#Override
public void run() {
while (true) {
try {
server = new ServerSocket(9002);
clientSocket = server.accept();
try {
try {
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
String word = in.readLine();
Log.d(LOG_TAG, "***" + word + "***");
out.write(word);
out.flush();
} finally {
System.out.println("run closed");
clientSocket.close();
in.close();
out.close();
}
} finally {
System.out.println("Server closed");
server.close();
}
} catch (IOException e) {
System.err.println(e);
}
}
}
}
So many problems with this code. Here's a list of them:
You'd need to be a foreground service, or Android will eventually kill your service.
You're making a server socket and accepting a single connection to it, then making another in a loop. That's not how you do it. You make the server socket once, and accept() for each incoming connection
As a consequence of the above, the second time will always fail, because the port won't be immediately available unless you use a socket with SO_REUSEADDR set. see the setReuseAddress call on ServerSocket
You're catching all exceptions blindly. I would highly suspect you're throwing an exception and ignoring it, causing it all to not work
This code won't work on any cellular network, as a NAT will be put between you and the world.
Even on wifi you need to make sure your network allows incoming connections to your device. The default on most home routers is not to.
Related
I have written a client to run on an android device (android 6) and when the server is up and running it connects, however when the server is down the socket() call should throw an exception however it doesn't.
I originally tried it using the NDK and ran into a very similar issue (Android NDK socket connect() returning 0 when it should fail whilst on 3g).
I am assuming this is a bug with android at this point but any insight into a solution or work around would be much appreciated.
The code in question:
public class Client implements Runnable{
private Socket socket;
private InetAddress IP;
private int port;
public Client(int port){
try {
this.IP = InetAddress.getByName(server ip);
}
catch(UnknownHostException e){
Log.d("App1", "Unknown Host, connection failed");
System.exit(1);
}
this.port = port;
Log.d("App1", "initialised");
}
#Override
public void run(){
try {
this.socket = new Socket(this.IP, this.port);
Log.d("FiX1", "Connected");
listen();
}
catch(IOException e){
Log.d("FiX1,","connection failed");
System.exit(1);
}
finally
{
try{
socket.close(); // dispose
}
catch(IOException e){
System.exit(1);
}
}
}
public void listen() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
String cominginText = "";
try {
cominginText = in.readLine();
Log.d("FiX1",cominginText);
} catch (IOException e) {
//error ("System: " + "Connection to server lost!");
System.exit(1);
break;
}
}
} catch (IOException e) {
System.exit(1);
}
}
}
The best solution I could find was to manually send an acknowledgement from the server that a connection had been made, the client would retry the connection if it did not receive this message within a certain time after it claimed to have connected.
There is a difference between a TCP connection "close" vs "disconnect".
If you close the socket connection from server using socket.close() then you will get exception in client side, if you try to read from that connection or vice versa.
However, if one side just disappears(shut down the program) then the other side has no way of knowing that. So the other side will wait for response for read call.
The TCP protocol was designed to be reliable in hostile communication environments and it will not normally decide a connection is closed just because it has not heard from the other side for a while.
I have two problems with an app that i have built for socket communication, first I'll try to explain what the app does and then I'll go into the details of those two problems.
First I click on a button, which starts a thread, which sends a multicast massage "group address" through a UDP socket. Once any of the devices receive the massage, they will send a response through TCP socket and my device will act as a server to the one that sent the response. So after debugging I found out the first problem which is clientSocket = serverSocket.accept(); sometimes gets stuck and the app will block everything and keep executing it, which might happen because the udp massage might never arrive at the destination which means there is no client for the tcp server that I've created.
First question: Is there any way to make the serverSocket.accept(); non-blocking or set a time out? I've tried serverSocket.setTimeSoOut() method, but that didn't work. Maybe this problem comes from something other than the UDP message?
The second problem is that if I press the button that calls the thread twice it will throw a BindException address already in use: Which will happen because of the re execution of serverSocket.bind(new InetSocketAddress(4125));. Is there any way to fix/avoid that?
Here are the threads that I'm using:
This one is called after I press the button:
private class ChatClientThread extends Thread {
DatagramSocket socket;
String sentence;
String modifiedSentence;
BufferedReader inFromUser;
DataOutputStream outToServer;
BufferedReader inFromServer;
Socket clientSocket;
ServerSocket serverSocket;
#Override
public void run() {
/*Socket socket = null;
DataOutputStream dataOutputStream = null;
DataInputStream dataInputStream=null;*/
clientSocket=null;
try {
String data="NewTask_"+EmpPhoneNumber;
serverSocket=new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(4125));
socket = new DatagramSocket(52276);
socket.setBroadcast(true);
InetAddress group = InetAddress.getByName(
"224.0.1.2");
DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(),
group, 52276);
socket.send(packet);
while(true){
clientSocket = serverSocket.accept();
ConnectThread ct=new ConnectThread(clientSocket);
ct.start();
}
} catch (UnknownHostException e) {
e.printStackTrace();
final String eString = e.toString();
TicketDetails.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(TicketDetails.this, eString, Toast.LENGTH_LONG).show();
}
});
} catch (IOException e) {
e.printStackTrace();
final String eString = e.toString();
TicketDetails.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(TicketDetails.this, eString, Toast.LENGTH_LONG).show();
}
});
} finally {
TicketDetails.this.runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
}
}
}
this one is called from the above thread as you can see:
private class ConnectThread extends Thread {
Socket socket;
String sentence;
String modifiedSentence;
BufferedReader inFromUser;
DataOutputStream outToServer;
BufferedReader inFromServer;
ConnectThread(Socket socket){
this.socket= socket;
}
#Override
public void run() {
DataInputStream dataInputStream = null;
DataOutputStream dataOutputStream = null;
Socket socket2 = null;
DataOutputStream dataOutputStream2= null;
DataInputStream dataInputStream2=null;
try {
while(true){
inFromUser = new BufferedReader( new InputStreamReader(System.in));
outToServer = new DataOutputStream(socket.getOutputStream());
inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
sentence = inFromUser.readLine();
modifiedSentence = inFromServer.readLine();
socket2 = new Socket(socket.getInetAddress().getHostAddress(), 4125);
dataOutputStream2 = new DataOutputStream(
socket2.getOutputStream());
String[] parts = modifiedSentence.split("_");
String partGive = parts[0].substring(4); // 004
String partEmpId = parts[1];
if(partGive.equals("GiveMeATask")&&Integer.parseInt(partEmpId)==empId){
dataOutputStream2.writeUTF(" "+"SolveProblemOrder_2");
dataOutputStream2.flush();
}
System.out.println("FROM SERVER: " + modifiedSentence);
if(modifiedSentence!=null) break;}
outToServer.close();
inFromServer.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (dataInputStream != null) {
try {
dataInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (dataOutputStream != null) {
try {
dataOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Those are two very commmon problems. I'll answer the two in reverse order.
The button you are talking about is creating a ServerSocket and binding it to a specific port. In your case, the port is 4125. From looking at your code, you don't seem to be closing that serversocket anywhere. When you click the button a second time, a second instance of ServerSocket tries to bind to the same port - but that port is still in use by the first ServerSocket. In that case, you get a bind exception. One port cannot be used by more than one ServerSocket. The solution would be to close the existing ServerSocket before creating a new one using serverSocket.close();
If you read the documentation, it clearly states what ServerSocket.accept() does: "[...] The method blocks until a connection is made." This is the "getting stuck" that you described. The thread that executes that code is put into a waiting position and continues only when a connection is made, then returns that new connection. The classic approach is to start a new thread that waits for incoming connections so that your main thread continues to execute and your whole application does not "freeze". Another approach would be a non-blocking framework that encapsulates all that overhead away from you, one of those is Apache MINA.
I would highly suggest to look into small example projects that deal with basic client/server behaviour as you will most likely deal with threads here.
First problem: It is very likely that your application is not receiving the UDP packages. If serverSocket.accept() doesn't get any clients it'll wait indefinitely for someone to connect. You could avoid this by using yet another thread that just accepts connections to avoid freezing your application. Another way would be to use Java's NIO classes that provide non-blocking IO for pretty much anything. That would require you to use ServerSocketChannel and related classes. (Quick googling also gave me this guide which seems fairly easy to follow).
Second problem: You need to close your ServerSocket once you're done using it. Otherwise the port will never be free again to be used by another ServerSocket.
Alternatively you could just leave the Socket open and remember that you already openend it (e.g. with a boolean field in your class).
I am trying to improve the speed at which the sockets transfer information but i am unsure how to do so. the pourpose of the code is to transfer a number, the date, and a short xml which is being sent in the form of a string.
this is the server code
import java.net.*;
import java.io.*;
public class SSocket extends Thread
{
private ServerSocket serverSocket;
public SSocket(int port) throws IOException
{
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(100000);
}
public void run()
{
System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
while(true)
{
try
{
Socket server = serverSocket.accept();
DataInputStream in = new DataInputStream(server.getInputStream());
int cor=in.readInt();
int i=0;
String transaccion = in.readUTF();
String fecha = in.readUTF();
System.out.println(cor);
System.out.println(transaccion);
System.out.println(fecha);
DataOutputStream out =
new DataOutputStream(server.getOutputStream());
if(transaccion!=null && fecha != null && cor>0){
out.writeInt(cor);
}
else {
out.writeInt(-1);
}
if (i==100){
out.flush();
i=0;
}
i++;
server.close();
}catch(SocketTimeoutException s)
{
System.out.println("Socket timed out!");
break;
}catch(IOException e)
{
e.printStackTrace();
break;
}
}
}
public static void main(String [] args)
{
int port = 1337;
try
{
Thread t = new SSocket(port);
t.start();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
the code for the client is
import java.net.*;
import java.io.*;
public class ClientSocket
{
public static void send(int correl, String transaccion, String fecha)
{
String serverName = "localhost";
int port = 1337;
try
{
Socket client = new Socket(serverName, port);
int i=0;
OutputStream outToServer = client.getOutputStream();
DataOutputStream out =
new DataOutputStream(outToServer);
out.writeInt(correl);
out.writeUTF(transaccion);
out.writeUTF(fecha);
InputStream inFromServer = client.getInputStream();
DataInputStream in =
new DataInputStream(inFromServer);
int corin=in.readInt();
if(corin>0){
Envio.updater(corin);
}
else {
}
if (i==100){
out.flush();
i=0;
}
i++;
client.close();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
i have done some reading on the mater and it seems that posible solutions are to use either a buffer or swich to a datagram. however my experience on working with sockets is rather limited and i am unsure which would be best to use for this situation or if there is another option i havent yet considered. this code will be moving many transactions and i wish to do it in as short time as posible.
thanks in advance
ps. sorry for my bad english it is not my first language
Datagrams imply UDP, which is an unreliable delivery protocol so you're not guaranteed to get all content. That's probably not what you want; I'd stay with plain Sockets (which use TCP, which has reliable delivery).
Will the same client be calling send() repeatedly and connecting to the same server each time? That is, will there be many messages going across a single connection, or will each message be to a different server, with only a single message (or only a few) going to each of the many servers? If there's just one server that a client is going to connect to and if a given client is going to send lots of messages, you should keep the Socket open between send() calls; setting up and tearing down Sockets is expensive, so you're paying a high price for making a new connection each time.
Also, your server appears to only be able to handle a single connection at a time: you accept a connection, read from it, and then close it and accept a new one. So to make this work for more than one client, you'll need to separate the logic for accepting connections onto a different thread from the logic that reads data. If you'll only have a few clients at a time, you can just start a new thread to read from each socket as you create it for a new client; if you'll have lots of clients (thousands), you'll probably need to look at NIO for its ability to service multiple sockets from a single thread. But I suspect you're a long way from having that problem, if you ever do, so I'd just spawn a new thread for each socket.
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 trying to test a scenario where one server accepts connections(one each time) from one client, using always the same ports (on the server and on the client side).
The purpose is to have 1 client application sending little pieces of data at a rate bigger than 100/min. The well obvious solution would be to have an always connected link between the client and the server, but this is production stuff, and that would require bigger changes in the code that is already implemented. With the solution we have implemented today, we always have +-1K of connections in TIME_WAIT, and I want to get rid of them.
I have implemented a simple tester, and the code is:
public class Server {
public static void main(String[] args) {
ServerSocket ssock = null;
try {
ssock = new ServerSocket();
ssock.bind(new InetSocketAddress(Common.SERVER_PORT));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
while(true){
try{
Socket cSock = ssock.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(cSock.getInputStream()));
reader.readLine();
PrintWriter writer = new PrintWriter(cSock.getOutputStream());
writer.println(Common.SERVER_SEND);
writer.flush();
reader.close();
writer.close();
cSock.close();
}catch (Exception e) {
System.out.println(e.getClass().getName() + ": " + e.getMessage());
}
}
}
}
public class Client {
public static void main(String[] args) throws Exception {
InetSocketAddress cliAddr = new InetSocketAddress(
InetAddress.getByName(args[0]),
Common.CLIENT_PORT);
InetSocketAddress srvAddr = new InetSocketAddress(
InetAddress.getByName(args[1]),
Common.SERVER_PORT);
for(int j=1;j<=50;j++){
Socket sock = null;
try{
sock = new Socket();
sock.setReuseAddress(true);
sock.bind(cliAddr);
sock.connect(srvAddr);
PrintWriter writer =
new PrintWriter(
sock.getOutputStream());
writer.println(Common.CLIENT_SEND);
writer.flush();
BufferedReader reader =
new BufferedReader(
new InputStreamReader(
sock.getInputStream()));
reader.readLine();
}catch (Exception e) {
System.out.println(e.getClass().getName() + ": " + e.getMessage());
System.exit(-1);
}finally{
if(sock!=null) sock.close();
System.out.println("Done " + j);
}
}
}
}
public class Common {
public static final int SERVER_PORT = 9009;
public static final int CLIENT_PORT = 9010;
public static final String CLIENT_SEND = "Message";
public static final String SERVER_SEND = "OK";
}
When executing the client and server, on windows hosts, in one client execution I always get
java.net.ConnectException: Connection timed out
When executing the client and the server in linux hosts, on some client executions I get a
java.net.NoRouteToHostException: Cannot assign requested address
I've been killing my head over this behavior. Can someone please tell me if it is possible to do what I want, and what I am doing wrong?
If you want to get rid of the TIME_WAIT state, don't be the peer that receives the close. Be the peer that initiates the close. In this case, close the connection immediately after reading the response, and have the server cycle around looking for another request so that it reads the EOF rather than just closing the connection immediately after sending the response. However this will only make the problem worse, as all the TIME_WAIT states will accumulate at the server rather than at the client. On the other hand, the server is now structured to accept multiple requests per connection, so then all you have to do is adapt the clients to use a connection pool and all your problems are solved.