I try to connect with my server by using socket on android. I want it to work like this; when i send a request to the server, if there is a response, call my response function. If the timeout of 500 ms happens (will check the exception and the boolean i set), i want to execute another function. But with this code im using, when i send something to the server and wait for response, it executes the onServerResponse function if there is a response and doesnt do anything(hangs) when there is not a response. How can i edit this code so it will throw a timeout exception when there is no response?
boolean control = false;
try{
Socket socket = new Socket();
socket.setSoTimeout(500);
socket.connect(new InetSocketAddress(InetAddress.getByName(SERVER_IP),SERVER_PORT));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"UTF-8"));
bw.write("asdasd\n");
bw.flush();
control = true;
int readInt = -1;
String read = null;
StringBuilder sb = new StringBuilder("");
while((readInt = socket.getInputStream().read()) != -1){
sb.append((char)readInt);
}
read = sb.toString();
if(read != null && read.trim().length() > 0){ onServerResponse(read); }
}catch(Exception e){ Log.v("Main", "GOT AN ERROR: "+e+control); }
Problem solved, see the comments for answer.
I'm not sure if this answers your question, but setSoTimeout only applies to reads on the socket after it is connected, not to establishing the connection itself. For that, use the socket.connect(SocketAddress address, int timout) overload.) overload. You probably want to use both.
Something like this would work:
Socket socket = new Socket();
InetAddress addr = InetAddress.getByName(SERVER_IP);
SocketAddress sockaddr = new InetSocketAddress(addr, SERVER_PORT);
// 500ms is too short, up to you.
// normal time would be 5 to 20 seconds, depends on network (intranet/internet)
socket.connect(sockaddr, 500);
// 500ms to timeout reading from the socket
socket.setSoTimeout(500);
Related
I have a software driver which communicates with a third-party controller; I have an API for using the latter but no visibility of its source code, and the supplier is not co-operative in trying to improve things!
The situation is as follows.
To send a request to the controller, I send an XML packet as the content of an HTTP POST to a servlet, which then sends me the response. The original code, implemented by a previous developer, works stably using java.net.Socket. However, our driver is implemented such that a new socket is created for EVERY request sent and, if the driver gets busy, the third-party controller struggles to keep up in terms of socket handling. In fact, their support guy said to me: "You really need to leave 5 seconds between each request...". This simply isn't commercially acceptable.
To improve performance, I wanted to try leaving our end of the socket open and reusing the socket pretty much indefinitely (given that connections can drop unexpectedly of course, but that's the least of my concerns and is manageable). However, whatever I seem to do, the effect is that if I use Comms.getSocket(false), a new socket is created for each request and everything works OK but bottlenecks when busy. If I use Comms.getSocket(true), the following happens:
Controller is sent first request
Controller responds to first request
Controller is sent second request (maybe 5 seconds later)
Controller never responds to second request or anything after it
postRequest() keeps getting called: for the first 12 seconds, the console outputs "Input shut down ? false" but, after that, the code no longer reaches there and doesn't get past the bw.write() and bw.flush() calls.
The controller allows both HTTP 1.0 and 1.1 but their docs say zilch about keep-alive. I've tried both and the code below shows that I've added Keep-Alive headers as well but the controller, as server, I'm guessing is ignoring them -- I don't think I have any way of knowing, do I ? When in HTTP 1.0 mode, the controller certainly returns a "Connection: close" but doesn't do that in HTTP 1.1 mode.
The likelihood is then that the server side is insisting on a "one socket per request" approach.
However, I wondered if I might be doing anything wrong (or missing something) in the following code to achieve what I want:
private String postRequest() throws IOException {
String resp = null;
String logMsg;
StringBuilder sb = new StringBuilder();
StringBuilder sbWrite = new StringBuilder();
Comms comms = getComms();
Socket socket = comms.getSocket(true);
BufferedReader br = comms.getReader();
BufferedWriter bw = comms.getWriter();
if (null != socket) {
System.out.println("Socket closed ? " + socket.isClosed());
System.out.println("Socket bound ? " + socket.isBound());
System.out.println("Socket connected ? " + socket.isConnected());
// Write the request
sbWrite
.append("POST /servlet/receiverServlet HTTP/1.1\r\n")
.append("Host: 192.168.200.100\r\n")
.append("Connection: Keep-Alive\r\n")
.append("Keep-Alive: timeout=10\r\n")
.append("Content-Type: text/xml\r\n")
.append("Content-Length: " + requestString.length() + "\r\n\r\n")
.append(requestString);
System.out.println("Writing:\n" + sbWrite.toString());
bw.write(sbWrite.toString());
bw.flush();
// Read the response
System.out.println("Input shut down ? " + socket.isInputShutdown());
String line;
boolean flag = false;
while ((line = br.readLine()) != null) {
System.out.println("Line: <" + line + ">");
if (flag) sb.append(line);
if (line.isEmpty()) flag = true;
}
resp = sb.toString();
}
else {
System.out.println("Socket not available");
}
return resp; // Another method will parse the response
}
To ease testing, I provide the socket using an extra Comms helper class and a method called getSocket(boolean reuse) where I can choose to always create a new socket or reuse the one that Comms creates for me, as follows:
public Comms(String ip, int port) {
this.ip = ip;
this.port = port;
initSocket();
}
private void initSocket() {
try {
socket = new Socket(ip, port);
socket.setKeepAlive(true);
socket.setPerformancePreferences(1, 0, 0);
socket.setReuseAddress(true);
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
br = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
System.out.println("### CREATED NEW SOCKET");
}
catch (UnknownHostException uhe) {
System.out.println("### UNKNOWN HOST FOR SOCKET");
}
catch (IOException ioe) {
System.out.println("### SOCKET I/O EXCEPTION");
}
}
public BufferedReader getReader() { return br; }
public BufferedWriter getWriter() { return bw; }
public Socket getSocket(boolean reuse) {
if (! reuse) initSocket();
return socket;
}
Can anyone help ?
If we assume that keep-alive thing is working as expected, I think the line while ((line = br.readLine()) != null) is a faulty one, as this is kind of infinity loop.
readline() returns null when there is no more data to read, e.g. a EOF, or when server/client closes the connection, that will break-down your reusing socket solution, since an open stream will never cause a null to a readLine() call, but blocking.
You need to fix the alg about reading a response (why not using implemented http client?), checking content-length, and when read the amount of required data from body, go for next loop by keeping the socket alive.
After that setting flag to true, you have to know what kind of data should be read(considering mime/content-type), besides that, the length of data, so reading data using readLine() may not be a good practice here.
Also make sure server allow for persistence connection, by checking if it respects it by responsing the same connection:keep-alive header.
inFromClientR.readLine() never stops. any ideas? Am I forgetting something?
Server:
/*{ some code:
send a file with a dataoutputstream to client using a new port(4000) and when transfer is done i want a responce message (e.g. OK) send back to server in the old port(6000)
}*/
ServerSocket listenTransferSocket = new ServerSocket(6000);
Socket connectionTransferSocket = listenTransferSocket.accept();
BufferedReader inFromClientR =
new BufferedReader(new InputStreamReader(connectionTransferSocket.getInputStream()));
System.out.println("Client's response to Transfer: " +inFromClientR.readLine());
Client:
/*{ some code:
receive the file on port (4000) and then the responce is sent to server using the following commands
}*/
Socket fileTransferSocket = new Socket("localhost", 6000);
DataOutputStream outToServerR =
new DataOutputStream(fileTransferSocket.getOutputStream());
outToServerR.writeBytes("Transfer completed " +'\n');
BufferedReader#readLine() tries to fill its buffer with 8192 bytes, regradless of any linefeeds it find meanwhile. Since you have the connection open, the receiving side will wait until 1) you have sent 8192 bytes, or 2) closes the connection.
You would be better off using some other framing mechanism, maybe an ObjectOutputStream/ObjectInputStream.
String line = null;
while ((line = inFromClientR.readLine()) != null) {
// do sth
}
How should one deal with clients disconnecting unexpectedly. I want to keep the server running/listening unless explicitly stated to close by the client.
For example, my server is listening and then the client is closed which causes the server's method to end - how can I get it to return to the beginning of the method as it were?
serverSocket = new ServerSocket(port);
clientSocket = serverSocket.accept();
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
BasicProtocol bp = new BasicProtocol(password);
out.println(bp.processInput(""));
String inputLine;
while((inputLine = in.readLine()) != null ){
System.out.println("Client asks: " + inputLine);
out.println(bp.processInput(inputLine));
}
As above, if a connection reset error occurs how can it wait to be reconnected to?
For instance you can have a while loop at the method with a boolean variable that is changed when the client wants to close. As such:
boolean isRunning = true;
while (isRunning) {
//Your current method - when client wants to disconnect just set isRunning = false;
}
I've got question, that I haven't found answer for yet. I have 2 devices with wifi each, that are sending special data. I want to show this data at the same moment on a tablet. There is a router with network, both tablet and that devices are connected to this network.
How to solve this? Should I use serversocket? I don't know if I explained it clear enought, if not, please ask. Thanks for any response.
I have the same application running on the company I work.
The "device" is a micro-controller based device that is implemented the lwIP (lightweight IP protocol) and it's listening to the port 83 and every 500ms the tablet goes and read new fresh data and plot it in a graph. Works like a charm.
(in case you'll be plotting charts, I used the AChartEngine and you can check on my profile a question/answer on it with some useful info)
the code below is a simplified version of what I'm doing. The complete version includes SEVERAL try{ } catch() { } in case it catches an exception it try closing the socket and return null;
public static String SendMessage(String message, String ip, int port) {
// Connect to host ==================================
Socket socket = new Socket();
socket.setSoTimeout(TIMEOUT);
InetSocketAddress addr = new InetSocketAddress(ip, port);
socket.connect(addr, TIMEOUT);
// Send Message ======================================
byte[] outputBuffer = message.getBytes();
socket.getOutputStream().write(outputBuffer);
// Zero the input buffer =============================
for (int i = 0; i < inputBuffer.length; i++) {
inputBuffer[i] = 0;
}
// Read the response ==================================
int count = 0;
do {
count = socket.getInputStream().read(inputBuffer);
} while (count != -1);
// Close connection ====================================
close(socket);
// Return message ======================================
return new String(inputBuffer).trim();
}
hope it helps,
happy coding.
1. Socket will be a good idea.
For Sending :
Socket s = new Socket();
s.connect(new InetSocketAddress("IP_ADDR",PORT_NO);
OutputStream o = s.getOutputStream();
PrintWriter pw = new PrintWriter(o);
pw.write(msg); // msg will be the data needed to send
For Receiving:
Socket s = new Socket();
s.connect(new InetSocketAddress("IP_ADDR",PORT_NO);
InputStream i = s.getInputStream();
InputStreamReader isr = new InputStreamReader(i);
BufferedReader br = new BufferedReader(isr);
String str = new String();
while((str=br.readLine())!=null){
System.out.println(str); // do whatever u want to do with str, the data read
}
I am writing a Java program to compute the http connection time for (lets say) 5 http connection (to different IP).
The first scenario is, without threading, the program connect and testing the http server one by one which mean when finish one server testing then proceed to another. In this scenario, the time taken is very long. Moreover, the timeout is not working properly, for example, I have set the
setConnectTimeout(5 * 1000);
setReadTimeout(5 * 1000);
but the time return by
long starTime = System.currentTimeMillis();
c.connect();
String line;
BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream()));
while ((line = in.readLine()) != null){
page.append(line);
elapseTime = System.currentTimeMillis() - starTime;
can be more than 5 second, some even go up to 30 second (but I set 5 second as timeout only).
So, I make the implementation to be multithreading. But the result is more rediculous. I can't even get one successful connection now.
Now my question is, can we establish multiple connection by using multiple thread? If answer is yes, what I have to notice to avoid the issue above?
Thank.
*Extra info*
1) I am computing the proxy connection speed, so, ya, the connection is proxy connection.
2) The threads that I created is around 100. I think it should be fine right?
How are you setting up your connections? Are you using a socket connection? If so, depending on how you setup your socket, you may find that the connection timeout value may be ignored
Socket sock = new Socket("hostname", port);
sock.setSoTimeout(5000);
sock.connect();
Will actually not set the connect timeout value, as the constructor will already attempt to connect.
SocketAddress sockaddr = new InetSocketAddress(host, port);
Socket sock = new Socket();
sock.connect(sockaddr, 5000);
Will more accurately connect with a timeout value. This may explain why your socket timeouts are not working.
public float getConnectionTime(){
long elapseTime = 0;
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ipAdd, portNum));
URL url;
StringBuilder page = new StringBuilder();
HttpURLConnection uc = null;
try {
uc = (HttpURLConnection)Main.targetMachine.openConnection(proxy);
// uc = (HttpURLConnection)Main.targetMachine.openConnection();
uc.setConnectTimeout(Main.timeOut);
uc.setReadTimeout(Main.timeOut);
long starTime = System.currentTimeMillis();
uc.connect();
// if (uc.getResponseCode() == HttpURLConnection.HTTP_OK){
// System.out.println("55555");
// }else System.out.println("88888");
String line;
BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream()));
while ((line = in.readLine()) != null){
page.append(line);
elapseTime = System.currentTimeMillis() - starTime;
}
} catch (SocketTimeoutException e) {
System.out.println("time out lo");
// e.printStackTrace();
return 9999; //if time out, use 9999 signal.
} catch (IOException e){
System.out.println("open connection error, connect error or inputstream error");
// e.printStackTrace();
return 9999;
}finally{
if (uc != null)
uc.disconnect();
}
// System.out.println(page);
return (float)elapseTime / 1000;
}