I'm reading a string from a buffer and writing it to a server. The problem I'm having is that the string never gets received by the server when I leave the socket open and write in a loop.
When I use this:
try {
Socket send = new Socket("localhost", 1490);
DataOutputStream out = new DataOutputStream(send.getOutputStream());
String message = null;
while ((message = buffer.get()) != null){
out.writeBytes(message);
}
out.close();
send.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
the server doesn't receive the string, but when I do this it works properly:
try {
String message = null;
while ((message = buffer.get()) != null){
Socket send = new Socket("localhost", 1490);
DataOutputStream out = new DataOutputStream(send.getOutputStream());
out.writeBytes(message);
out.close();
send.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
Obviously I don't want to keep opening and closing the socket, though. What is the problem?
You need to flush your socket every time you want to send a data packet.
Closing a socket forces an automatic flush and that explains why your data is getting sent on socket close.
The data is not being written to the socket even when you close it? (in your first snippet that is)
Also, have you tried to use the flush method? You can read about it here: http://docs.oracle.com/javase/1.4.2/docs/api/java/io/DataOutputStream.html#flush() and your code will look like:
try {
Socket send = new Socket("localhost", 1490);
DataOutputStream out = new DataOutputStream(send.getOutputStream());
String message = null;
while ((message = buffer.get()) != null){
out.writeBytes(message);
out.flush();
}
out.close();
send.close();
} catch (IOException ex) {
ex.printStackTrace();
}
Let me make a guess.
Does the buffer.get() method block? If so, then the problem is that out.writeBytes(message) does not guarantee that the entire byte representation to be pushed to the server. Instead. there is a good chance that your client has buffered bytes waiting to be flushed through to the server.
If this is what is going on, then calling flush after each call to writeBytes will fix the problem.
But if the buffer.get() method doesn't block, then calling flush won't make any difference. In fact, it will just increase the network traffic. So adding the flush "just in case" is a bad idea.
Another possibility is that there is something wrong with the server-side code.
Related
everyone. I'm coding a function that connects to a server by using Class HttpURLConnection. In the code, I establish a connection, call getOutputStream() and getInputStream() methods in order. Then I disconnect the connection. After this, I try to get data which has been obtained by getInputStream() method, but the compiler reminds NullPointerException.
Code in below:
DataOutputStream out = null;
InputStreamReader inStrReader = null;
BufferedReader reader = null;
HttpURLConnection connection = null;
try {
URL postUrl = new URL(null, url, new sun.net.www.protocol.https.Handler());
connection = (HttpURLConnection) postUrl.openConnection();
...//some setting methods
connection.connect();
out = new DataOutputStream(connection.getOutputStream());
out.writeBytes(JSONObject.toJSONString(param));
out.flush();
out.close();
inStrReader = new InputStreamReader(connection.getInputStream(), "utf-8");
reader = new BufferedReader(inStrReader);
connection.disconnect(); //<--HERE, release the connection
StringBuilder stringBuilder = new StringBuilder();
for (String line = reader.readLine(); line != null; line = reader.readLine()) { //<--null pointer
stringBuilder.append(line);
}
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inStrReader != null) {
try {
inStrReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
After debug attempts, When I move the disconnection line to the last line in finally module, everything will be ok. But I'm confused, which happens when I already assgined the 'inputstream' value to 'reader'.
Thanks a lot.
Assigning isn't equal to reading, reader.readLine() start read from connection.
InputStreamReader is using the connection to read bytes, you disconnect before it read the bytes using the connection
An InputStreamReader is a bridge from byte streams to character
streams: It reads bytes and ...
Remember it is an "stream". You need to have an active connection to read from stream. Close the connection only after you have retrieved your data from stream.
You're doing everything in the wrong order. It doesn't make sense.
You're disconnecting and then expecting to be able to read from the connection. Total nonsense here. Normally you shouldn't disconnect at all, as you interfere with HTTP connection pooling. Just remove it, or, if you must have it, do it after all the closes.
You're closing in the wrong order, but you don't need to close inStrReader at all. Closing the BufferedReader does that. Just remove all the code for inStrReader.close().
You're closing out twice. Don't do that.
connect() happens implicitly. You don't need to call it yourself.
new URL(url) is sufficient. You haven't needed to provide the HTTPS Handler since about 2003.
I saw some posts about this but I still can't find an answer.
This is how my server interacts with the client:
public void run () {
try {
//Read client request
InputStream is = server.getInputStream();
byte[] buff = new byte[1024];
int i;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((i = is.read(buff, 0, buff.length)) != -1) {
bos.write(buff, 0, i);
System.out.println(i + " bytes readed ("+bos.size()+")");
}
is.close();
is = null;
//Do something with client request
//write response
OutputStream os = server.getOutputStream();
os.write("server response".getBytes());
os.flush();
os.close();
os = null;
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
And this is the client side:
public void run() {
try {
InetAddress serverAddr = null;
serverAddr = InetAddress.getByName("10.0.2.2");
socket = new Socket(serverAddr, 5000);
//Send Request to the server
OutputStream os = socket.getOutputStream();
os.write(jsonRequest.toString().getBytes("UTF-8"));
os.flush();
os.close();
os = null;
//Read Server Response
InputStream is = socket.getInputStream();
byte[] buff = new byte[1024];
int i;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((i = is.read(buff, 0, buff.length)) != -1) {
bos.write(buff, 0, i);
System.out.println(i + " bytes readed ("+bos.size()+")");
}
is.close();
is = null;
//Do something with server response
} catch (UnknownHostException uhe) {
sendCallbackError(uhe);
} catch (IOException ioe) {
sendCallbackError(ioe);
}
}
As you can see, the client connects and send a request. Server read that request then writes a response that the client will read.
The problem with this code is the OutputStream.close() in the client and InputStream.close() in the server. As stated in the Javadocs, closing the stream will close the Socket. The result is that when the client tries to read the server response, the Socket is already closed.
I've managed to overcome this by calling Socket.shutdownInput and Socket.shutdownOutput instead. However I am still thinking whether this is the proper way of doing it
As a note, closing the streams with close() when server writes the response or when the client reads it doesn't create problems (I would guess the closing is synchronized between client and server).
So my questions are:
Is using the Socket shutdown methods a proper way?
Can I keep closing the last streams with close() (when sending and reading
response from server)
Could it happen that closing with shutdown would keep some data in
the buffer and wouldn't be sent?
You can do the following:
try{
}catch(){
}finally{
if(is!=null){
is.close();
}
if(os!=null){
os.close();
}
}
The problem with this code is the OutputStream.close() in the client and InputStream.close() in the server. As stated in the Javadocs, closing the stream will close the Socket.
Correct but the InputStream in the server isn't connected directly to a Socket: it is connected to something you don't know anything about. You can close it with impunity, although again you don't need to close it at all. You can close the OutputStream in the server if you like: although, again, as it isn't connected directly to a Socket, it may or may not have any effect other than flushing.
To address your actual question, you don't need to close the output stream in the client, but you do need to send an appropriate Content-Length: header. That way the server knows how much to read from the client. If this is only a GET request the content-length may well be zero. You don't need to call shutdownOutput(), although I guess there is nothing to stop you, and calling shutdownInput() doesn't do anything to the network anyway so again there is no point to it.
I got to implement a chat in my application. Connection to a server is made using sockets. I should register to that server and the server will aknowledge that with a reply.
I have implemented this in a single method where I send the command using a BufferedWriter, and then start reading from the input stream until it tells me there is no more data.
I read properly the server reply. However, I never get the negative value from the second in.read call and thus my method stays blocked in the while loop (in the conditionnal statement where I make that call).
How should this be done with sockets? I usually do that with files or other input streams without problem.
If I should read only the bytes I am supposed to read, does that mean that I either have to:
Know in advance the length of the server response?
or make the server send a code to notify it has finished to send its response?
Currently I am doing the following:
private String sendSocketRequest(String request, boolean skipResponse) throws ChatException {
if (!isConnected()) openConnection();
try {
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()), 2048);
out.append(request);
out.flush();
out = null;
} catch (IOException e) {
LogHelper.error("Unable to send socket request: " + request, e);
throw new ChatException("Unable to send socket request: " + request, e);
}
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()), 2048);
StringBuffer response = new StringBuffer();
char[] buffer = new char[2048];
int charsRead = -1;
// >>>>>>>> This is where it gets blocked <<<<<<<<<
while ((charsRead = in.read(buffer)) >= 0) {
if (charsRead > 0) response.append(new String(buffer, 0, charsRead));
}
return response.toString();
} catch (IOException e) {
LogHelper.error("Unable to read socket response: " + request, e);
throw new ChatException("Unable to read socket response: " + request, e);
}
}
Connection to the server is made with the following method:
public synchronized void openConnection() throws ChatException {
try {
socket = new Socket(Constants.API_CHAT_SERVER_ADDRESS, Constants.API_CHAT_SERVER_PORT);
socket.setKeepAlive(true);
LogHelper.debug("CHAT >> Connected to the chat server: " + Constants.API_CHAT_SERVER_ADDRESS);
} catch (UnknownHostException e) {
LogHelper.error("Unable to open chat connection", e);
throw new ChatException("Unable to open chat connection", e);
} catch (IOException e) {
LogHelper.error("Unable to open chat connection", e);
throw new ChatException("Unable to open chat connection", e);
}
}
The amount of data to be sent/received over a socket based connection is protocol dependend and not known to the TCP/IP stack, but only to the application layer.
The protocol used is developer dependend ... ;-) so coming to your questions:
If I should read only the bytes I am supposed to read, does that mean that I either have to:
Know in advance the length of the server response?
Yes, this is one possibility.
or make the server send a code to notify it has finished to send its response?
Also yes, as this is another possibility. Common markers are \n or \r\n. The NUL/'\0' character also might make sense.
A third option is to prefix each data chunk with a constant number of bytes describing the amount of bytes to come.
Instead of dealing with bytes, maybe it's simpler handling instances of ad-hoc classes, like - for instance - a Message class:
The server:
// Streams
protected ObjectInputStream fromBuffer = null;
protected ObjectOutputStream toBuffer = null;
// Listening for a new connection
ServerSocket serverConn = new ServerSocket(TCP_PORT);
socket = serverConn.accept();
toBuffer = new ObjectOutputStream(socket.getOutputStream());
fromBuffer = new ObjectInputStream(socket.getInputStream());
// Receiving a new Message object
Message data = (Message)fromBuffer.readObject();
The client then sends a message by simply:
// Sending a message
Message data = new Message("Hello");
toBuffer.writeObject(data);
Message can be as complex as needed as long as its members implement Serializable interface.
I am writing a client application that will receive a continuous flow of data through tcp/ip. The problem I'm having is that the buffered reader object isn't receiving any data and is hanging at the readline method.
The way the server works is that you connect to it, and then send authentication information in order to receive data. The gist of my code is below
socket = new Socket(strHost, port);
authenticate();
inStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
process(inStream);
authenticate()
{
PrintWriter pwriter = new PrintWriter(socket.getOutputStream(), true);
pwriter.println(authString);
}
process(BufferedReader bufferedReader)
{
while((line = bufferedReader.readLine()) != null)
dostuff
}
I created a sample server application that sends data the way (I think) the server is sending data and it connects, and receives and processes the data fine. I can connect to the server fine in my application. I can also telnet to the server and write the authentication string and receive a flood of data using telnet. However my application just hangs at readLine with the server and I'm out of idea's why.
The data coming in (through telnet atleast) looks like a continuous stream of the following:
data;data;data;data;data
data;data;data;data;data
Why is my app hanging at readline, am I not outputting the authentication line correctly? I'm not receiving any errors...
EDIT
My sample server code (which is working correctly)...again this is only mimicking the way I think the real server is running but I can connect to both in my application just not receive data from the real server.
public static void main(String[] args) throws IOException
{
ServerSocket serverSocket = null;
try
{
serverSocket = new ServerSocket(1987);
}
catch (IOException e)
{
System.out.println("Couldn't listen on port: 1987");
System.exit(-1);
}
Socket clientSocket = null;
try
{
clientSocket = serverSocket.accept();
}
catch (IOException e) {
System.out.println("Accept failed: 1987");
System.exit(-1);
}
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String something;
while ((something = in.readLine()) != null)
{
while(true)
{
out.println(message);
}
}
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}
Firstly you should call BufferedReader.ready() before calling readLine(), as the ready() will tell you if it's ok to read.
PrintWriter doesn't throw I/O Exception so the write may have failed without your knowledge which is why there is nothing to read. Use PrintWriter.checkError() to see if anything as gone wrong during the write.
You ought to set up the input and output streams on the Socket at the same time before you write anything down the pipe. If your reader is not ready when the other end tries to write you will get a broken pipe in the server and it won't send any more data. Telnet sets up read and write before you have written or read anything.
You can make use of Wireshark to tell if the server is actually sending data.
BufferdReader.readLine() reads lines, i.e. sequences of characters ended with \r or \r\n. I guess that your server writes its output into one single line. Your telnet output proves this assumption. Just use PrintWriter.println() at server side.
this work with me
with socket without flush
void start_listen()
{
String result1="";
char[] incoming = new char[1024];
while (!s.isClosed())
{
try {
int lenght = input.read(incoming);
result1 = String.copyValueOf(incoming,0,lenght);
}
catch (IOException e)
{
e.printStackTrace();
}
Log.d("ddddddddddd",result1);
}
I am trying to send a file (an image sent as a byte array) with the client and then the server should receive said byte array to make further use of it. However when I click on the "send" to send the image the file transfer starts (as I get a sentImage.jpg in my Desktop) but it gets stuck for some reason I can't figure out and the image never gets correctly sent.
Here's the part that receives from the server (it already accepted the connection):
public void run(){
try {
byte[] receivedData = new byte[1024];
BufferedInputStream bis = new BufferedInputStream(client.getInputStream());
// while(bis.read() != -1){
s.acquireUninterruptibly();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\Admin\\Desktop\\sentImage.jpg"));
while ((incoming = bis.read(receivedData)) != -1) {
bos.write(receivedData, 0, incoming);
}
s.release();
n.release();
bis.close();
bos.flush();
// }
} catch (IOException e) {
e.printStackTrace();
}
}
and the client is sending here:
public void sendImageResult() {
new Thread(new Runnable() {
public void run() {
try {
int inside = 0;
Socket socket = new Socket("localhost", 4444);
File myImageFile = new File("C:\\Users\\Admin\\Desktop\\test.jpg");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myImageFile));
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream( ));
byte[] byteArray = new byte[1024];
while ((inside = bis.read(byteArray)) != -1){
bos.write(byteArray,0,inside);
}
bis.close();
bos.flush();
} catch (UnknownHostException ex) {
System.out.println("No se pudo establecer la conexión.");
ex.printStackTrace();
} catch (FileNotFoundException fnf){
fnf.printStackTrace();
} catch(IOException ioe){
ioe.printStackTrace();
}
}
}).start();
}
It does not appear that the OutputStream (bos) that is used to write to disk is being closed. This could lead to unexpected results.
As jt said, the OutputStream writing to disk is not being closed, but neither is the OutputStream being used to send the data, nor is the Socket being closed from the sending side. The sending side may be buffering the data at the tcp level, waiting for more bytes before sending the last packet. You are calling flush, but that can be ignored, it's not guaranteed to work like you expect. Another thing to try is calling shutdownOutput on the Socket and seeing if that forces it to flush. You can also try setTcpNoDelay(true) when you open the Socket. If none of that works, get a tcp trace program (I like tcpdump) and use it to see if the packets are actually being sent, it will at least narrow it down to either the send or receive end of things.