what im trying to do:
client connects to server
server sends READY
client takes screenshot and sends it
server processes image
server sends READY
client takes screenshot and sends it
server processes image
...
i have a working client and server:
Client() {
try {
socket = new Socket(host, 4444);
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
int ix = 0;
while (true) {
switch (in.readInt()) {
case Var.READY:
image = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
ByteArrayOutputStream byteArrayO = new ByteArrayOutputStream();
ImageIO.write(image,"PNG",byteArrayO);
byte [] byteArray = byteArrayO.toByteArray();
out.writeInt(byteArray.length);
out.write(byteArray);
System.out.println("send screen " + ix++);
break;
}
}
} catch (UnknownHostException e) {
System.err.println("Don't know about host");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection " + e.getMessage());
System.exit(1);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
Server:
public class ServerWorker implements Runnable {
private Socket socket = null;
DataInputStream in = null;
DataOutputStream out = null;
ServerWorker() {
}
synchronized void setSocket(Socket socket) {
this.socket = socket;
try {
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
notify();
}
public synchronized void run() {
int ix = 0;
try {
while (true) {
out.writeInt(Var.READY);
int nbrToRead = in.readInt();
byte[] byteArray = new byte[nbrToRead];
int nbrRd = 0;
int nbrLeftToRead = nbrToRead;
while(nbrLeftToRead > 0){
int rd =in.read(byteArray, nbrRd, nbrLeftToRead);
if(rd < 0)
break;
nbrRd += rd; // accumulate bytes read
nbrLeftToRead -= rd;
}
//Converting the image
ByteArrayInputStream byteArrayI = new ByteArrayInputStream(byteArray);
BufferedImage image = ImageIO.read(byteArrayI);
System.out.println("received screen " + ix++);
//image.flush();
File of = new File("RecvdImg" + ix + ".jpg");
ImageIO.write(image, "PNG" ,of);
System.out.println("Sleeping 1..");
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
So whats the question you might ask?
Well, am i doing it right?
Activity monitor tells me the client side takes about 40% of cpu constantly, that cant be good.
Just wondering if anyone could point me in the right direction to making the code more efficient.
Client could detect if the image has changed, and if it hasn't it could send to the server a flag indicating to reuse the previous image received. Or you can "diff" the image and send only the changed areas to the server, which will recompose the image. That reduces bandwidth usage and perhaps also CPU usage.
Also, the client should sleep a while in the receiving endless loop, after the switch.
In my opinion you should avoid using infinit-loops like
while (true)
Loops like
while(!connectionAborted)
are better in such situations.
Also you should take a look at
Socket.setSoTimeout()
SoTimeout cancels the reading-process of i.e. in.readInt() after an specific amount of time, depending on your parameter.
The result is that at this line a SocketTimeoutException is thrown, but your code is not stuck at this codeline and can react on i.e. different user inputs.
Related
I'm trying to build a transparent proxy in Java with the ability to record data that passed through to be viewed later in wireshark.
I was able to get the proxy working correctly with this snippet
private static final int BUFFER_SIZE = 8192;
...
public void run() {
PcapHandle handle = null;
PcapDumper dumper;
try {
InetAddress addr = InetAddress.getByName("localhost");
PcapNetworkInterface nif = Pcaps.getDevByAddress(addr);
int snapLen = 65536;
PcapNetworkInterface.PromiscuousMode mode = PcapNetworkInterface.PromiscuousMode.PROMISCUOUS;
int timeout = 10;
handle = nif.openLive(snapLen, mode, timeout);
dumper = handle.dumpOpen("cap.pcap");
byte[] buffer = new byte[BUFFER_SIZE];
try {
while (true) {
int bytesRead = mInputStream.read(buffer);
if (bytesRead == -1)
break; // End of stream is reached --> exit
mOutputStream.write(buffer, 0, bytesRead);
dumper.dumpRaw(Arrays.copyOfRange(buffer, 0, bytesRead));
mOutputStream.flush();
}
} catch (IOException e) {
// Read/write failed --> connection is broken
}
dumper.close();
} catch (PcapNativeException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (NotOpenException e) {
e.printStackTrace();
}
}
As you may notice I'm using Pcap4J to store raw bytes into a pcap file. The saving of the bytes works well but when I try to open it on wireshark it shows this message:
Error
And every packet shows as malformed. Ideally I would be seeing TCP and CQL (Cassandra) packets.
Can anyone tell me what I'm doing wrong here?
I wrote a Java socket server which will keep connection alive until client disconnected. And my client code will keep pushing message to this server app.
But when I run those programs a while, I also seem an unusual condition that Server will hangs while reading input stream from client within unpredictable period. It always hang at inData.read(b) because I see it printed "receiving..." on log when this problem occurred"; even I killed my client, server app still hangs right there.
But when I press Ctrl+C at the console which runs server app after this problem occurred, it will continue to work. This is really annoying.
Is there anyway to solve this Unusual problem nicely?
Server Code:
static ServerSocket server;
try {
server = new ServerSocket("1234");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Socket socket = null;
String inIp = null;
BufferedInputStream inData;
BufferedOutputStream outData;
while (true) {
try {
synchronized (server) {
socket = server.accept();
}
inIp = String.valueOf(socket.getInetAddress());
if (Log4j.log.isEnabledFor(Level.INFO)) {
Log4j.log.info("Incoming connection " + inIp);
}
while (true) {
inData = new BufferedInputStream(socket.getInputStream());
outData = new BufferedOutputStream(socket.getOutputStream());
String reply = "Hey";
byte[] b = new byte[10240];
String data = "";
int length;
if (Log4j.log.isEnabledFor(Level.INFO)) {
Log4j.log.info("InetAddr = " + inIp + ", receiving...");
}
// read input stream
length = inData.read(b);
data += new String(b, 0, length);
if (Log4j.log.isEnabledFor(Level.INFO)) {
Log4j.log.info("Data Length: " + length + ", Received data: " + data);
}
// output result
outData.write(reply.getBytes());
outData.flush();
}
} catch (Exception e) {
String tempStr = e.toString();
Log4j.log.error("Service error during executing: " + tempStr);
}
}
Client Code:
Socket client = new Socket();
InetSocketAddress isa = new InetSocketAddress("127.0.0.1", "1234");
String data = "Hi";
while(true) {
try {
if(!client.isConnected())
client.connect(isa, 30000);
BufferedOutputStream out = new BufferedOutputStream(client.getOutputStream());
BufferedInputStream in = new BufferedInputStream(client.getInputStream());
// send msg
out.write(data.getBytes());
out.flush();
System.out.println("Message sent, receiving return message...");
// get return msg
int length;
byte[] b = new byte[10240];
// read input stream
length = in.read(b);
retMsg = new String(b, 0, length);
System.out.println("Return Msg: " + retMsg);
Thread.sleep(60000);
} catch (java.io.IOException | InterruptedException e) {
System.out.println("Socket Error!");
System.out.println("IOException :" + e.toString());
}
}
try {
server = new ServerSocket("1234");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Don't write code like this. The catch block should be at the end, and all the code that depends on the success of new ServerSocket should be inside the try block.
synchronized (server) {
socket = server.accept();
}
Synchronization is not necessary here.
while (true) {
inData = new BufferedInputStream(socket.getInputStream());
outData = new BufferedOutputStream(socket.getOutputStream());
A large part of the problem, if not all of it, is here. You keep creating new buffered streams, every time around this loop, which means that anything the previous streams have buffered is thrown away. So you are losing input. You should create both these streams before the loop.
while(true) {
try {
if(!client.isConnected())
client.connect(isa, 30000);
This is pointless. Remove. You haven't shown how the client socket was created, but if you created it unconnected you should have connected it before entering this loop.
BufferedOutputStream out = new BufferedOutputStream(client.getOutputStream());
BufferedInputStream in = new BufferedInputStream(client.getInputStream());
Here again you must create these streams ahead of the loop.
I'm trying to make a very basic example of a network connection where I use an ObjectOutputStream, ObjectInputStream and sockets. The client sends the string "Hello" to the server. As you see this string is sent 10 times with the very same ObjectOutputStream. Then the server sends the string "Goodbye" to the client. The console should display 10 times the string "hello" and 10 times the string "Goodbye". But they are shown only one time. I read in many threads about the method reset() of the ObjectOutputStream. But it does not seem to work for me. Any ideas what the problem is? I've already tried many different things without success.
Here is the client:
try
{
Socket socket = new Socket("localhost", 5555);
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
int i = 10;
while (i > 0)
{
//send String
out.writeObject("Hello");
out.flush();
out.reset();
//receive String
String result = (String) in.readObject();
System.out.println(result);
i--;
}
} catch (IOException e)
{
e.printStackTrace();
} catch (ClassNotFoundException e)
{
e.printStackTrace();
} finally
{
out.close();
in.close();
socket.close();
}
Here is the server:
try
{
ServerSocket server = new ServerSocket(5555);
while(true)
{
try
{
Socket client = server.accept();
ObjectInputStream in = new ObjectInputStream(client.getInputStream());
ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
//receive String
String input = (String) in.readObject();
System.out.println(input);
out.writeObject("Goodbye");
out.flush();
out.reset();
} catch(IOException e1)
{
e1.printStackTrace();
} catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
} catch(IOException e2)
{
e2.printStackTrace();
}
Your server is only reading and writing once to each accepted socket. So the client can't possibly read an object ten times.
Your server also isn't closing the stream when it's finished.
I'm currently working on an Android app which sends an string and a file to a java server app running on remote computer. This java server app should find the index on the file and send back the value of this index (The file structure is: index value. Example: 1 blue) The file is properly sent and received on the remote machine and I have a method which finds the value of the received index on the file. But when I'm trying to send the found value back to the phone I get an exception (closed socket), but I'm not closing the socket or any buffer. I'm not sure if the socket which is closed is the mobile app socket or the java server app socket. I'm using the same socket I use to send to receive (which is the way to work on Android). Sending the answer back to the phone is what my project is missing and is what I need help in. Here is my code:
Client app (Android app):
private class HeavyRemProcessing extends AsyncTask<String, Void, String>
{
protected String doInBackground(String... urls)
{
begins = System.currentTimeMillis();
remoteExecution();
ends= System.currentTimeMillis();
procTime=ends-begins;
aux= Long.toString(procTime);
return aux;
} //doInBackground() ends
protected void onPostExecute(String time)
{
textView1.setText("Result: "+result+". Processing Time: "+time+" milisecs");
}// onPostExecute ends
} //HeavyRemProcessing ends
public void executor(View view)
{
key="74FWEJ48DX4ZX8LQ";
HeavyRemProcessing task = new HeavyRemProcessing();
task.execute(new String[] { "????" });
} //executor() ends
public void remoteExecution()
{
// I have fixed IP and port I just deleted
String ip; //SERVER IP
int port; // SERVER PORT
try
{
cliSock = new Socket(ip, port);
file= new File("/mnt/sdcard/download/Test.txt");
long length = file.length();
byte[] bytes = new byte[(int) length];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream out = new BufferedOutputStream(cliSock.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(cliSock.getInputStream()));
int count;
key=key+"\r\n";
out.write(key.getBytes());
while ((count = bis.read(bytes)) > 0)
{
out.write(bytes, 0, count);
} //It works perfectly until here
//// PROBABLY HERE IS THE PROBLEM:
out.flush();
out.close();
fis.close();
bis.close();
result= in.readLine(); //RECEIVE A STRING FROM THE REMOTE PC
}catch(IOException ioe)
{
// Toast.makeText(getApplicationContext(),ioe.toString() + ioe.getMessage(),Toast.LENGTH_SHORT).show();
}
}catch(Exception exp)
{
//Toast.makeText(getApplicationContext(),exp.toString() + exp.getMessage(),Toast.LENGTH_SHORT).show();
}
} //remoteExecution ends
Java Server App (Remote PC)
public void receivingFile()
{
System.out.println("Executing Heavy Processing Thread (Port 8888).");
try
{
serverSocket = new ServerSocket(8888);
InputStream is = null;
OutputStream os= null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
BufferedOutputStream boSock =null;
DataOutputStream dataOutputStream=null;
int bufferSize = 0;
try
{
socket = serverSocket.accept();
System.out.println("Heavy Processing Task Connection from ip: " + socket.getInetAddress());
} catch (Exception ex)
{
System.out.println("Can't accept client connection: "+ex);
}
try
{
is = socket.getInputStream();
dataOutputStream = new DataOutputStream(socket.getOutputStream());
bufferSize = socket.getReceiveBufferSize();
}
catch (IOException ex)
{
System.out.println("Can't get socket input stream. ");
}
try
{
fos = new FileOutputStream(path);
bos = new BufferedOutputStream(fos);
}
catch (FileNotFoundException ex)
{
System.out.println("File not found. ");
}
byte[] bytes = new byte[bufferSize];
int count;
System.out.println("Receiving Transfer File!.");
while ((count = is.read(bytes)) > 0)
{
bos.write(bytes, 0, count);
}
System.out.println("File Successfully Received!.");
fos.close();
bos.flush();
bos.close();
is.close();
result= obj.searchIndex();
System.out.println("Found: "+result); //This correctly print the found value
dataOutputStream.writeUTF(result);
dataOutputStream.flush();
dataOutputStream.close();
System.out.println("Data sent back to the Android Client. ");
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
} // receivingFile() ends
Please if someone can help me I will really appreciate it. I'm thinking is something probably related with the buffers and the socket. My java server app throws an exception: "Closed Socket"... Thanks for your time,
Alberto.
I think your problem is that you closing the outputstream before closing the inputstream. This is a bug in android. Normally in java closing outputstream only flushes the data and closing inputstream causes the connection to be closed. But in android closing the outputstream closes the connection. That is why you are getting closed socket exception,
Put the statements
out.flush();
out.close();
after
result=in.readLine();
or just avoid those statements(out.flush and out.close). I had also faced a similar problem. See my question
My JAVA application sends a command to server (command=filename.ini). When the server receives this command it sends filename.ini contents through Socket.
The first problem I had was receiving only partial contents of the file. That happened when in the code I used while(in.available()!=0){//write bytes} because in.available() does not know how big/long the content of the file is. If I use while((numBytesRead = dis.read(buffer)) != -1){//write bytes} the loop will never terminate since the Socket connection remains always open. My question is how else can I terminate the loop once every byte has been received? Please help me I have tried everything. I understand where the mistake is but I don't know how to fix it.
The following is the part of the code I have at the moment:
public class TCPClient {
protected Socket s = null;
public DataInputStream in = null;
public TCPClient(InetAddress ipa, int port) {
Socket s1 = null;
try { //Open the socket.
s1 = new Socket(ipa.getHostAddress(), port);
} catch (IOException ex) {
System.out.println("Error opening socket!");
return;
}
s = s1;
try { //Create an input stream.
in = new DataInputStream(new BufferedInputStream(s.getInputStream()));
} catch (Exception ex) {
System.out.println("Error creating input stream!");
}
}
public synchronized byte[] receive() {
byte[] buffer = new byte[0];
ByteArrayOutputStream getBytes = new ByteArrayOutputStream();
try {
while (in.available() == 0) {
} //Wait for data.
} catch (IOException ex) {
}
try {
int numBytesRead;
buffer = new byte[1024];
while ((numBytesRead = dis.read(buffer, 0, 1024)) != -1) { //LOOP NEVER ENDS HERE BECAUSE CONNECTION IS ALWAYS OPEN
getBytes.write(buffer, 0, numBytesRead);
}
} catch (IOException ex) {
}
return (getBytes.toByteArray());
}
}
You need to define a micro protocol to say the receiver how long is the file, or just close the connection on the server after finishing sending the file. First method is preferred, since it is a little bit more robust. On the client you should have a timeout too in order to avoid to wait forever in case of network problems.
Clarification for micro protocol: before sending the file itself send a 32 (or 64 if needed) bit integer containing the file length. The client should read that integer and then start retrieving the file.