I am creating some client-side socket software to read events from a server. (For example, streaming stock quotes).
PROBLEM: .read(b); is returning immediately with a value of -1. This causes an infinte loop and the phone becomes very hot. Additionally, all checks to s.isConnected(), isOpen(), isBound() return true. Essentially the socket looks connected. (This is an error scenario, so any value of .setSoTimeout(x) has no effect. 12 minutes, or leave empty. The .read(b) always returns -1 immediately).
When I write to it later, via the getOutputStream(), I receive an exception EPIPE (broken pipe).
Here's the core code (log statements/value checks omitted for brevity).
s.connect(new InetSocketAddress(host, port), CONNECT_TIMEOUT_MILLIS);
byte[] b = new byte[1024];
while (s.isConnected()) {
int bytesToRead = s.getInputStream().read(b);
if (bytesToRead <= 0) {
LOGGER.debug("no bytes read? trying again.");
continue;
}
processFrame(b);
}
If I cycle the 3g on the phone, it works fine. Sometimes it gets into this weird state.
Question
Am I doing something wrong? Is this the expected behavior? Is there existing code I could look at to show the right way to do socket programming on Android?
I use the following code without problem:
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
myLineProcess(line); //here you process you line result
}
good luck.
If read(byte[], ...) returns < 0, the peer has closed the connection, so you must close the socket and exit the loop. There will never be any more data.
Input streams are blocking, so the only way read(byte[], ...) can return zero is if you specify a zero length buffer or a zero length, depending on which overload you call. As you aren't doing that, it will never return zero.
Instead it will do exactly what it says in the Javadoc: either return -1 meaning EOS, or block until at least one byte of data is available.
Am I doing something wrong?
Almost everything. Your loop testing for <= 0 is completely pointless and completely incorrect. And so is testing isConnected(). That only tells you whether you ever connected this Socket. It doesn't change with the state of the connection. The return code of -1 tells you that. Your loop should read:
while ((bytesToRead = s.getInputStream().read(b)) > 0)
{
// do something with b[0..bytesToRead -1].
}
s.close();
Well i don't know whether this would be the appropriate answer for this, but still i will like to give you the code, which does works well every time.
Please keep it simple,
Try using InputStream, InputStreamReader, BufferedReader, OutputStream, PrintWriter.
Client Side:
Socket s = new Socket();
s.connect(new InetSocketAddress("Server_IP",Port_no),TimeOut);
// Let Timeout be 5000
Server Side:
ServerSocket ss = new ServerSocket(Port_no);
Socket incoming = ss.accept();
For Reading from the Socket:
InputStream is = s.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
boolean isDone = false;
String s = new String();
while(!isDone && ((s=br.readLine())!=null)){
System.out.println(s); // Printing on Console
}
For Writing to the Socket:
OutputStream os = s.getOuptStream();
PrintWriter pw = new PrintWriter(os)
pw.println("Hello");
Related
I've came across a problem and it's been bothering me for quite a time now. I'm working on a web server and the problem is that when i try to read the client request, the read() method blocks and waits for more bytes to read but there is none and the end of stream is reached which normally read() methods should retutn -1 but it won't until i hit the stop loading button on the browser.
ServerSocket ss = new ServerSocket(3000);
Socket s = ss.accept();
InputStream in = s.getInputStream();
int i;
while((i = in.read()) != -1){
//some processing here
}
How can i fix this problem? thank you very much
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br=new BufferedReader(isr);
String number;
list.clear();
while ((number=br.readLine())!=null){
list.add(number);
}
while i trying to read the data from the buffered reader,i got the data.But i can't exit from the while loop if number equals null.
readLine() returns null at stream, and not before, and end of stream on a socket only occurs when the peer has closed the connection. Your expectations appear to be misplaced.
It's because you are failing at understanding the readline function and your implementation of it. You are reading data from your buffer and comparing the data to null, which is obviously not what you are wanting. So here is how I like to read data from a TCP socket.
while(statement == true){
int count = bufferedInputStream.read(buffer);
if (count == -1){
// Socket has been closed
} else {
// Data has been read.
// Do comparison here.
}
}
Hope this helps.
I'm writing a program that uses multiple SSL connections. Basically, my code has to 3 separate programs that can connect to one another and communicate through SSL sockets.
The problem I'm having is with blocking I/O. For example, my class CLAFrame.java has to be able to detect and handle input from a stream, but also be able to carry out other functions. I don't want this to block the entire program and freeze it up waiting for input (like it is now).
Here's how I had it set up.
static void initializeCLAConnection(){
try {
SSLServerSocketFactory sslserversocketfactory =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslserversocket =
(SSLServerSocket) sslserversocketfactory.createServerSocket(3577);
SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();
InputStream inputstream = sslsocket.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
OutputStream outputstream = sslsocket.getOutputStream();
OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream);
BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter);
input=bufferedreader;
output=bufferedwriter;
System.out.println("Connection accepted from: "+sslserversocket.getInetAddress());
String string=null;
//RECEIVING INPUT
while(input.ready()){
System.out.println("CLA receiving msg");
// while ((string = input.readLine()) != null) {
string=input.readLine();
System.out.println(string);
/*
* HEADERS FOR INPUT RECEIVED
* Format: VAL Ryan Smith
* VAL - requesting validation id
*/
String header=null;
String rest=null;
header=string.substring(0, 3);
if(string.length()>3){
rest=string.substring(4, string.length()-1);
}
//perform actions based on input
switch(header){
case "VAL ":
//do something
requestValidationID(rest);
break;
default:
break;
}
}
}
// System.out.println("Successfully established CLA server on SSL port 3577");
catch (Exception exception) {
exception.printStackTrace();
}
}
Note - Previously, I had my while loop setup as
while ((string = input.readLine()) != null) {
However, clearly this will block I/O until input is received. I then switched to
while(input.ready()){
This has stopped the blocking but now my buffer (input) is not receiving anything at all when I write to the stream.
Is there a better way to do this? This program is set up as a GUI so I need the buffer to be able to receive input, but I also need to be able to simultaneously use other buttons and functions on the program without it blocking everything.
Should I make it multithreaded? A thread for reading the buffer and another for all other functions? I'm a bit confused what to try next.
Any input/advice would be greatly appreciated, thanks!
You're trying to re-invent the wheel here. There are many non-blocking frameworks out there, all built on top of Java NIO (which provides non-blocking IO functionality in Java).
Netty is one such example, very fast and not the highest abstraction.
Edit:
Considering this is a school project, and that you just need to be able to do things simultaneously, I'd say what you want isn't non-blocking code, you just want your blocking code to run in a separate thread.
See Java's Executors for that.
I have a Socket listening on some x port.
I can send the data to the socket from my client app but unable to get any response from the server socket.
BufferedReader bis = new BufferedReader(new
InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = bis.readLine()) != null)
{
instr.append(inputLine);
}
This code part reads data from server.
But I can't read anything from server until unless the Socket on the server is closed.
Server code is not under my control to edit something on it.
How can I overcome this from client code.
Thanks
Looks like the server may not be sending newline characters (which is what the readLine() is looking for). Try something that does not rely on that. Here's an example that uses the buffer approach:
Socket clientSocket = new Socket("www.google.com", 80);
InputStream is = clientSocket.getInputStream();
PrintWriter pw = new PrintWriter(clientSocket.getOutputStream());
pw.println("GET / HTTP/1.0");
pw.println();
pw.flush();
byte[] buffer = new byte[1024];
int read;
while((read = is.read(buffer)) != -1) {
String output = new String(buffer, 0, read);
System.out.print(output);
System.out.flush();
};
clientSocket.close();
To communicate between a client and a server, a protocol needs to be well defined.
The client code blocks until a line is received from the server, or the socket is closed. You said that you only receive something once the socket is closed. So it probably means that the server doesn't send lines of text ended by an EOL character. The readLine() method thus blocks until such a character is found in the stream, or the socket is closed. Don't use readLine() if the server doesn't send lines. Use the method appropriate for the defined protocol (which we don't know).
For me this code is strange:
bis.readLine()
As I remember, this will try to read into a buffer until he founds a '\n'. But what if is never sent?
My ugly version breaks any design pattern and other recommendations, but always works:
int bytesExpected = clientSocket.available(); //it is waiting here
int[] buffer = new int[bytesExpected];
int readCount = clientSocket.read(buffer);
You should add the verifications for error and interruptions handling too.
With webservices results this is what worked for me ( 2-10MB was the max result, what I have sent)
Here is my implementation
clientSocket = new Socket(config.serverAddress, config.portNumber);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while (clientSocket.isConnected()) {
data = in.readLine();
if (data != null) {
logger.debug("data: {}", data);
}
}
Hello all my friends,
I am trying to send a long string through socket connection but I have them in two parts so I get an error while doing my processs.
In client I am sending the file,
BufferedWriter bufferedOut = null;
BufferedReader in = null;
socket = new Socket("192.168.0.15",4444);
bufferedOut = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
bufferedOut.write(xmlInString, 0, xmlInString.length());
/**
* wait for response
*/
byte[] buf = new byte[10000];
int actualNumberOfBytesRead = socket.getInputStream().read(buf);
String responseLine = new String(buf, 0, actualNumberOfBytesRead);
In the server,
BufferedReader in = null;
PrintWriter out = null;
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out = new PrintWriter(client.getOutputStream(), true);
//get the input
byte[] buf = new byte[10000];
int actualNumberOfBytesRead = client.getInputStream().read(buf);
line = new String(buf, 0, actualNumberOfBytesRead);
//send back
out.println(result);
How I can get my string as one part ? Can you please show me where is my mistake on the code ?
Thank you all
You will need a loop to repeatedly read from the input stream, concatenating the read data together each time, until you reach the end of the string.
Edit - a little more detail. If you are looking at transmitting multiple such strings/files, then see #arnaudĀ“s answer. If all your looking to to is send 1 big string then:
On the sender side, create the output stream, send the data (as you have done), and then don't forget to close the stream again (this will also perform a flush which ensure the data gets sent over the wire, and informs the other end that there is no more data to come).
On the recipient site, read the data in a loop until the input stream ends (read(buf) returns -1), concatenating the data together each time in one big buffer, then close the input stream.
Also, please read my comment about sending a file as bytes rather than a string. This is particularly important for XML files, which have rather special rules for encoding detection.
When using a TCP socket, you are handling "streams". That is, there is no delimitation between messages by default. By proceeding as you do, you may read part of a message, or worse, read more than a message.
The most common way to proceed is to delimit your messages. You can use DataInputStream/DataOutputStream which encodes strings into bytes and use the first bytes to indicate it's length. That way, it knows how many bytes it should read on the receiver end.
DataOutputStream out = null;
DataInputStream in = null;
Socket socket = new Socket("192.168.0.15",4444);
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
out.writeUTF(xmlInString);
out.flush(); // to ensure everything is sent and nothing is kept in the buffer.
// wait for response
String responseLine = in.readUTF();
Then, adjust the server code accordingly.
When using Buffered outputs with sockets, which is advised for performance reasons, it is advised to flush() after you wrote the message to ensure that everything is actually sent over the network and nothing is kept in the buffer.
Your initial problem probably occurred because your message requires several TCP/IP packets and in your server, you read only the first one(s) which just arrived.