I have a PC server and an android client; my android client start a socket connection to server.
While I am connected to server, I also receive data from server to android client;
Here is my code:
Socket socket = null;
DataOutputStream out = null;
DataInputStream in = null;
InputStream inputStream = null;
OutputStream outputStream = null;
...
public void connectToTCP()
{
try
{
socket = new Socket(HOST_ADDRESS, PORT);
socket.setSoTimeout(30000);
outputStream = socket.getOutputStream();
out = new DataOutputStream(outputStream);
inputStream = socket.getInputStream();
in = new DataInputStream(inputStream);
Log.e("TCP-", "Connected");
while (socket.isConnected()){readBytes();}
}
catch (UnknownHostException e)
{
Log.e("Error in tcp connection","Unknown Host");
}
catch (IOException e)
{
Log.e("Error in tcp connection", "Couldn't get I/O for the connection");
}
}
public void readBytes() throws IOException
{
if (in.available() > 0)
{
byte[] buffer = new byte[in.available()];
if (buffer.length > 0)
{
if (mListener != null)
{
int numberOfBytes = in.read(buffer);
mListener.tcpConnectionDataReceived(buffer, numberOfBytes);
}
}
}
}
but my problem is in performance. I tested the code on the device and I noticed (from task manager) that the app consume a lot of resources (CPU usage is more than 50%) but when I stop reading from socket by deleting this while loop while (socket.isConnected()){readBytes();} CPU usage becomes less than 1%.
Any ideas to solve this?
You readBytes() method will return immediately if no data is available. Since it's in a tight loop, you're essentially continuously checking if there is something available, wasting a lot of CPU power.
With the code you show, you would be better off doing a plain blocking read (i.e. remove the available() check altogether, and use a reasonable, fixed-size buffer).
You should sleep between calls to readBytes() - you basically created an endless loop if no data is available and thus in.available() > 0 is false.
Or if this is in its own background thread, just do blocking reads when you know that more data is expected.
Related
I am attempting to read an input stream from a socket provided by a web browser client. Every approach I have taken has got the same results thus far, it just hangs and I don't know why. I have tried mark() marking the read limit to what is available and still no go.
inputStream.mark(inputStream.available());
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024 * 9];
int read;
while((read = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, read);
}
byte[] bytes = outputStream.toByteArray();
I have also tried clientSocket.shutdownInput() to tried to fix this issue, still no good.
Here is my attempt below:
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Server {
public static void main(String[] args)
{
ServerSocket server = null;
try {
// Server is listening on port 3001
server = new ServerSocket(3001, 1, InetAddress.getByName("localhost"));
server.setReuseAddress(true);
// running infinite loop for getting
// client request
while (true) {
// socket object to receive incoming client
// requests
Socket client = server.accept();
// Displaying that new client is connected
// to Server
System.out.println("New client connected"
+ client.getInetAddress()
.getHostAddress());
// create a new thread object
ClientHandler clientSock
= new ClientHandler(client);
// This thread will handle the client
// separately
new Thread(clientSock).start();
}
}catch (IOException e) {
e.printStackTrace();
}
}
// ClientHandler class
private static class ClientHandler implements Runnable {
private final Socket clientSocket;
// Constructor
public ClientHandler(Socket clientSocket)
{
this.clientSocket = clientSocket;
}
public void run() {
InputStream inputStream = null;
OutputStream clientOutput = null;
try {
inputStream = clientSocket.getInputStream();
inputStream.mark(inputStream.available());
clientSocket.shutdownInput();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024 * 9];
int numRead;
while((numRead = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, numRead);
}
byte[] bytes = outputStream.toByteArray();
String payloadString = new String(bytes, StandardCharsets.UTF_8);
System.out.println(payloadString);
clientOutput = clientSocket.getOutputStream();
clientOutput.write(("HTTP/1.1 \r\n" + "200 OK").getBytes());
clientOutput.write(("ContentType: " + "text/html" + "\r\n").getBytes());
clientOutput.write("\r\n".getBytes());
clientOutput.write("Hello World!".getBytes());
clientOutput.write("\r\n\r\n".getBytes());
clientOutput.flush();
inputStream.close();
clientOutput.close();
try{
clientSocket.close();
}catch(Exception ex){
ex.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Any help would be most appreciated! Thank you.
browsers suggests you should toss this all in the garbage and use HTTP, because, well, browsers.
But, if you insist, there are two problems here.
You've made it crazy complicated.
You can take all of that code and replace it all with this simple little line:
byte[] bytes = in.readAllBytes();
That replaces the lines starting with in.mark(in.available()) (this line does nothing at all, I have no idea where you got this from. If you think it is supposed to do something specific, you might want to mention that. Because it doesn't do anything. mark is useful if you ever reset, which you aren't, and you don't need to here, hence, useless), all the way to `byte[] bytes =...;
sockets don't close unless sender goes out of its way to close it
Your read code (yours, or the much simpler one-liner above) reads everything until the stream closes. In your second snippet, you close it right away, which obviously doesn't work. You cannot know when to close it, the sender does this job. Evidently it's not doing it.
I advise you to adapt protocols that pre-roll sizes, so you know how much to read and aren't dependent on closing the socket just to signal that the data is sent.
For example:
byte[] sizeRaw = in.readNBytes(4);
int size = ByteBuffer.wrap(bytes).getInt();
byte[] bytes = in.readNBytes(size);
You will of course have to adjust the sending code to send the size first (as a 32-bit value, big endian). One way or another you have to look at the sending code here. Either fix it so that it closes once done, or, better yet, adjust it so it sends size first.
I have a big problem. I have developped a client-server application. A client thread sends a serialized object to the server and the server sends back a serialized object. Currently I'm using one server and 10 client threads and after about 30 seconds I get the error message from each client thread (IOException):
No buffer space available (maximum connections reached?): connect
If I'm looking in netstat then I see that there are a lot of connections created and it is growing and growing and all connections are in TIME_WAIT state.
I don't know why. I close the sockets in the server and in the clients everytime in a finally block. Here is some code:
In the server I have in socketHandlerThread:
ServerSocket serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(5000);
while(true) {
Socket socket = serverSocket.accept();
}
The new socket is then put on a LinkedBlockingQueue and a worker thread takes the socket and makes the following:
try {
outputStream = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
outputStream.flush();
inStream = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
ClientRequest clientRequest = (ClientRequest) inStream.readObject();
...
outputStream.writeObject(serverResponse);
outputStream.flush();
} catch....
} finally {
if (inStream != null) {
inStream.close();
}
if (outputStream != null) {
outputStream.close();
}
if (socket != null) {
socket.close();
}
}
On the client side I have the following code:
try {
socket = new Socket(host, port);
outputStream = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
outputStream.flush();
inputStream = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
outputStream.writeObject(request);
outputStream.flush();
Object serverResponse = inputStream.readObject();
} catch....
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
if (socket != null) {
socket.close();
}
}
Can somebody help? I really don't know what mistake I made. I seems that the sockets get no closed but I don't know why.
Could it be the problem that I put the sockets on a queue on the server side so that the socket is somehow copied?
Edit: If I put the client and the server each on a different Amazon EC2 classic instance running Linux AMI then it works. Could it be a problem with Windows or is the problem simply that I was running the Clients and servers on the same machine (my local pc)?
Does somebody see a bug in my code?
Edit2: As said above on EC2 instances it works but if I use netstat it shows still a lot of lines saying TIME_WAIT.
Here are screenshots:
https://drive.google.com/file/d/0BzERdJrwWrNCWjhReGhpR2FBMUU/view?usp=sharing
https://drive.google.com/file/d/0BzERdJrwWrNCOG1TWGo5YmxlaTg/view?usp=sharing
First screenshot is from windows. "WARTEND" means "WAITING" (it is german).
The second screenshot is from Amazon EC2 (to the left the client machine, to the right the server machine).
TIME-WAIT is entered after the connection is closed at both ends. It lasts for a couple of minutes, for data integrity reasons.
If the buffer problem is due to TIME-WAIT states at the server, the solution is to make the server be the peer that first receives the close. That will shift the TIME-WAIT state to the client, where it is benign.
You can do that by putting your server-side request handling into a loop, so that it can handle multiple requests per connection, and so that the server only closes the socket when it reaches end of stream on it.
for (;;)
{
try
{
ClientRequest clientRequest = (ClientRequest) inStream.readObject();
...
outputStream.writeObject(serverResponse);
outputStream.flush();
}
catch (EOFException exc)
{
break;
}
}
If you then implement connection-pooling at the client, you will massively reduce the number of connections, which will further reduce the incidence of the buffer problem.
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 have created a server by using ServerSocket. After that, I have created Client using Socket, and connect to this server.
After that, I do "some stuff" with InputStream and OutputStream is taken from Socket Object. But, I don't really understand inputStream and outputStream so much. Here is my simple code :
private Socket sock = null;
private InputStream sockInput = null;
private OutputStream sockOutput = null;
...
String msg = "Hello World";
byte[] buffer = null;
try {
sockOutput.write(msg.getBytes(), 0, test.length());
sockOutput.write("Hello StackOverFlow".getBytes(), 0, test.length());
buffer = new byte[test.length()];
sockInput.read(buffer, 0, test.length());
System.out.println(new String(buffer));
sockInput.read(buffer, 0, test.length());
System.out.println(new String(buffer));
} catch (IOException e1) {
e1.printStackTrace();
}
The result will be : "Hello World" and "Hello StackOverFlow".
Here is server side code :
private int serverPort = 0;
private ServerSocket serverSock = null;
public VerySimpleServer(int serverPort) {
this.serverPort = serverPort;
try {
serverSock = new ServerSocket(this.serverPort);
}
catch (IOException e){
e.printStackTrace(System.err);
}
}
// All this method does is wait for some bytes from the
// connection, read them, then write them back again, until the
// socket is closed from the other side.
public void handleConnection(InputStream sockInput, OutputStream sockOutput) {
while(true) {
byte[] buf=new byte[1024];
int bytes_read = 0;
try {
// This call to read() will wait forever, until the
// program on the other side either sends some data,
// or closes the socket.
bytes_read = sockInput.read(buf, 0, buf.length);
// If the socket is closed, sockInput.read() will return -1.
if(bytes_read < 0) {
System.err.println("Server: Tried to read from socket, read() returned < 0, Closing socket.");
return;
}
System.err.println("Server: Received "+bytes_read
+" bytes, sending them back to client, data="
+(new String(buf, 0, bytes_read)));
sockOutput.write(buf, 0, bytes_read);
// This call to flush() is optional - we're saying go
// ahead and send the data now instead of buffering
// it.
sockOutput.flush();
}
catch (Exception e){
System.err.println("Exception reading from/writing to socket, e="+e);
e.printStackTrace(System.err);
return;
}
}
}
public void waitForConnections() {
Socket sock = null;
InputStream sockInput = null;
OutputStream sockOutput = null;
while (true) {
try {
// This method call, accept(), blocks and waits
// (forever if necessary) until some other program
// opens a socket connection to our server. When some
// other program opens a connection to our server,
// accept() creates a new socket to represent that
// connection and returns.
sock = serverSock.accept();
System.err.println("Server : Have accepted new socket.");
// From this point on, no new socket connections can
// be made to our server until we call accept() again.
sockInput = sock.getInputStream();
sockOutput = sock.getOutputStream();
}
catch (IOException e){
e.printStackTrace(System.err);
}
// Do something with the socket - read bytes from the
// socket and write them back to the socket until the
// other side closes the connection.
handleConnection(sockInput, sockOutput);
// Now we close the socket.
try {
System.err.println("Closing socket.");
sock.close();
}
catch (Exception e){
System.err.println("Exception while closing socket.");
e.printStackTrace(System.err);
}
System.err.println("Finished with socket, waiting for next connection.");
}
}
public static void main(String argv[]) {
int port = 54321;
VerySimpleServer server = new VerySimpleServer(port);
server.waitForConnections();
}
My question is :
When I use sockOutput.write and I can get back those message back by sockInput.read. So, those message has been saved, right? If this true, does it saved on Server I have created or just saved in some other thing such as Socket Object.
If I have written to socket String A1, A2,... An so I will receive A1, A2, ... An String respectively, right?
A socket is an abstraction that you use to talk to something across the network. See diagram below...
In Java, to send data via the socket, you get an OutputStream (1) from it, and write to the OutputStream (you output some data).
To read data from the socket, you get its InputStream, and read input from this second stream.
You can think of the streams as a pair of one-way pipes connected to a socket on the wall. What happens on the other side of the wall is not your problem!
In your case, the server has another socket (the other end of the connection) and another pair of streams. It uses its InputStream (2) to read from the network, and its OutputStream (3) to write the same data back across the network to your client, which reads it again via its InputStream (4) completing the round trip.
Client Server
1. OutputStream -->\ /--> 2. InputStream -->
Socket <--> network <--> ServerSocket |
4. InputStream <--/ \<--3. OutputStream <--
Updated: in reply to comment:
Note that the streams and sockets just send raw bytes; they have no notion of a "message" at this level of abstraction. So if you send X bytes and another X bytes, then read X bytes and read another X bytes, then your system behaves as if there are two messages, because that's how you've divided up the bytes.
If you send X bytes, and another X bytes, then read a reply of length 2X, then you might be able to read a single combined "message", but as you've noticed, the underlying implementation of the streams can choose when to deliver chunks of bytes, so it might return X bytes, then X bytes, later, or 2X at once, or 0.5X four times...
InputStream and OutputStream are two completely separate streams. What you write into one has no a priori relation to what you read from the other. The InputStream gives you whatever data the server decides to send to you. I would also like to comment on this piece of your code:
sockOutput.write(msg.getBytes(), 0, test.length());
sockOutput.write("Hello StackOverFlow".getBytes(), 0, test.length());
You use the length of a string test (not shown in your code), which has nothing to do with the byte array you are passing as the first argument. This can cause an ArrayIndexOutOfBoundsException or truncation of your intended message.
Additional comments to your updated question
Reviewing your server-side code, it is not quite correctly written. You need to have try { handleConnection(...); } finally { socket.close(); } to ensure proper cleanup after an error, as well as when completing normally. Your code never closes anything on the server side.
Finally, and most critically, your entire code is written in a way that can result in a deadlock. Normally you need a separate thread to read and to write; otherwise the following may happen:
You attempt to write some data to the output;
The server reads it and tries to respond with data in your input;
But, since the buffers are too small, you don't manage to send everything because the server wants to first send something to you, then receive the rest; but you don't get to the receiving part before you have sent everything you've got.
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.