Hello I have an app that connect to a remote server using sockets
socket = new Socket();
socket.connect(new InetSocketAddress(Ip, portNum), 7000);
I have 2 methods send & receive
the scenario in send is
PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
in method receive
String msg = "";
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (in.ready()) {
msg = msg + (char) in.read();
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
in AsyncTask of a different class I call
send();
String response=receive();
The above code is not sending or receiving without a wait period
i.e
Thread.sleep(2000);
I know sleep is a bad approach
what is the best scenario should I use?
Is it better to make an AsyncTask within send method and another one for receive method.
Here is where I use sleep and what data send & receive
client.send(some sql statement representED as json format);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// sql select result represented as json
String RESULT = client.recive();
Likely your server is not listening before you try to connect. Though this is unclear from the code you have posted. You'll need to show both server and client code there.
Related
I'm having the following problem in java: I am developing and app using java.net.Socket. It looks like that: There is a server with a thread which accepts and adds new client, and another thread which reads data from sockets and does "something" with it. Next to it there are clients. Client has data reader thread as well as a separate thread. I send the data as simple as:
socket.getOutputStream().write((content+"\n").getBytes());
on the client side and read it on the server like:
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String received;
while(true) {
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
received = reader.readLine();
if(received == null) {
break;
}
System.out.println("SERVER " + received);
increaseReceivedCounter(1);
} catch(SocketException e) {
break;
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
System.out.println("SERVER RECEIVED "+ getReceivedCounter() + " MESSAGES!");
}
Now I just set the client to send some amount of messages like this:
try {
int n = 1000;
System.out.println("sending "+ n +" messages to " + client);
for(int i=0 ; i<n ; ++i) {
socket.getOutputStream().write((content+"\n").getBytes());
}
System.out.println("done sending " + n + " messages");
} catch (IOException e) {
e.printStackTrace();
}
The problem is that not all of the messages are transferred to a server. I have been looking for some solution for this but didn't manage to achieve 100% reliability. Is it even possible? I also tried with read instead of readLine but the result is the same: sometimes even 90% data loss. I think while server is working on the received data it ignores incoming packets and they're just lost.
Edit
Sockets initializations:
serverSocket = new ServerSocket(Server.PORT);//PORT = 9876, whatever
for the data reader on server side:
socket = serverSocket.accept();
on the client:
socket = new Socket("127.0.0.1", Server.PORT)
This is not an 'efficiency issue'. It is a bug in your code.
The problem is that not all of the messages are transferred to a server.
No, the problem is that you are losing data at the server. This is because you keep recreating BufferedReaders. You should create it once for the life of the socket.
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Remove this line.
The way you have it, you will lose data every time the prior BufferedReader has, err, buffered.
You also need to close the socket.
I'm building a Java client application which needs to send a message to a server and receive a response afterwards. I can send the message successfully, the problem is that I can't get the response because I get an IO exception ("Socked is closed") when trying to read the 'BufferedReader'.
This is my code, so far:
public class MyClass {
/**
* #param args the command line arguments
*/
#SuppressWarnings("empty-statement")
public static void main(String[] args) {
JSONObject j = new JSONObject();
try {
j.put("comando", 1);
j.put("versao", 1);
j.put("senha", "c4ca4238a0b923820dcc509a6f75849b");
j.put("usuario", "1");
j.put("deviceId", "1");
} catch (JSONException ex) {
System.out.println("JSON Exception reached");
}
String LoginString = "{comando':1,'versao':1,'senha':'c4ca4238a0b923820dcc509a6f75849b','usuario':'1','deviceId':'1'}";
try {
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
Socket clientSocket = new Socket("10.1.1.12", 3333);
System.out.println("Connected to the server successfully");
PrintWriter outToServer = new PrintWriter(clientSocket.getOutputStream(),true);
outToServer.println(j.toString());
outToServer.close();
System.out.println("TO SERVER: " + j.toString());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String resposta = inFromServer.readLine();
System.out.println("FROM SERVER: " + resposta);
clientSocket.close();
} catch (UnknownHostException ex) {
System.out.println("Could not connect to the server [Unknown exception]");
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
I know that the socket is being closed because of the OutToServer.close() but closing the stream is the only way to send the message. How should I approach this situation?
flush() is not the case when it comes with new PrintWriter(, true).
The real problem is that you are closing the PrintWriter outToServer which wraps the underlying InputStream, again, came from the Socket.
When you close the outToServer you're closing the whole socket.
You have to use Socket#shutdownOutput().
You don't even have to close the output if you want to keep the socket's in/out channels for further communications.
flush() when you are done with any writeXXX. Those writeXXX practically don't mean you sent those bytes and characters to other side of the socket.
You may have to close the output, and output only, to signal the server that you sent all you had to send. This is really a matter of the server-side socket's desire.
final Socket socket = new Socket(...);
try {
final PrintStream out = new PrintStream(socket.getOutputStream());
// write here
out.flush(); // this is important.
socket.shutdownOutput(); // half closing
// socket is still alive
// read input here
} finally {
socket.close();
}
Try to call outToServer.flush()
That will try to flush the data from the buffer, although it still not guarantees that it will be sent.
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'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.
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);
}