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?
Related
In some tutoral-based codes, I connected a C# web application to a Java socket server through my web application's WebMethod in a webservice. Unfortunately this is happening pretty slowly. For example, when the Java server echoes some data to the C# client I get the following results:
Size of data sent= 32MB, total time= 980 ms (no problem)
Size of data sent= 4MB, total time= 530 ms (becomes somewhat slower)
Size of data sent= 1MB, total time= 520 ms (absolutely bottlenecked)
Size of data sent= 1kB, total time= 516 ms (this must be some constant latency of something)
I've read that people can make real-time communications (~60/s) and sometimes even millions of streams/s with some server apps. What could be the problem with my implementation? It is sending multiple messages over a single open connection, so the object creation overhead should only show up for the first message? Why am I getting ~500 ms overhead on my messaging?
The C# webmethod is initiated when the web-app starts and connects to the same Java server for every call to this webmethod.
public static IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
public static IPAddress ipAddress = ipHostInfo.AddressList[0];
public static IPEndPoint remoteEP = new IPEndPoint(ipAddress, 9999);
// Create a TCP/IP socket.
public static Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public static int z = 0;
[WebMethod]
public BenchmarkData_ StartClient()
{
lock(lck)
{
z++;
if (z == 1)
{
sender.Connect(remoteEP);
}
}
int bytesRec = 0;
int boy = 0;
byte[] bytes = new byte[1024 * 1024];
int bytesSent = 0;
SocketFlags sf = new SocketFlags();
Stopwatch sw = new Stopwatch(); Stopwatch sw2 = new Stopwatch();
#region r
lock (lck)
{
sw.Start();
// Data buffer for incoming data.
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// This example uses port 11000 on the local computer.
// Create a TCP/IP socket.
sender.ReceiveBufferSize = 1024 * 1024;
sender.ReceiveTimeout = 1;
// Connect the socket to the remote endpoint. Catch any errors.
try
{
Console.WriteLine("Socket connected to {0}", sender.RemoteEndPoint.ToString());
// Encode the data string into a byte array.
byte[] msg = Encoding.ASCII.GetBytes("This is a test<EOF>");
// Send the data through the socket.
bytesSent = sender.Send(msg);
// Receive the response from the remote device.
sw.Stop();
sw2.Start();
while ((bytesRec = sender.Receive(bytes)) > 0)
{
boy += bytesRec;
}
Console.WriteLine("Echoed test = {0}", Encoding.ASCII.GetString(bytes, 0, bytesRec));
// Release the socket.
// sender.Shutdown(SocketShutdown.Both);
// sender.Close();
sw2.Stop();
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
#endregion
return new BenchmarkData_() { .... };
}
Here is the Java code (half-pseudo code)
serverSocket=new ServerSocket(port); // in listener thread
Socket socket=serverSocket.accept(); // in listener thread
// in a dedicated thread per connection made:
out=new BufferedOutputStream( socket.getOutputStream());
in=new DataInputStream(socket.getInputStream());
boolean reading=true;
ArrayList<Byte> incoming=new ArrayList<Byte>();
while (in.available() == 0)
{
Thread.sleep(3);
}
while (in.available() > 0)
{
int bayt=-2;
try {
bayt=in.read();
} catch (IOException e) { e.printStackTrace(); }
if (bayt == -1)
{
reading = false;
}
else
{
incoming.add((byte) bayt);
}
}
byte [] incomingBuf=new byte[incoming.size()];
for(int i = 0; i < incomingBuf.length; i++)
{
incomingBuf[i] = incoming.get(i);
}
msg = new String(incomingBuf, StandardCharsets.UTF_8);
if (msg.length() < 8192)
System.out.println("Socket Thread: "+msg);
else
System.out.println("Socket Thread: long msg.");
OutputStreamWriter outW = new OutputStreamWriter(out);
System.out.println(socket.getReceiveBufferSize());
outW.write(testStr.toString()); // 32MB, 4MB, ... 1kB versions
outW.flush();
Problem solved in replacement of
while ((bytesRec = sender.Receive(bytes))>0)
{
boy += bytesRec;
}
with
while (sender.Available <= 0) ;
while (sender.Available>0)
{
bytesRec = sender.Receive(bytes);
boy += bytesRec;
}
now its in microseconds for 1kB reads instead of 500ms. Because its checking a single integer instead of trying to read on whole buffer? Maybe. But it now doesnt read all the message sent from server. It needs some type of header to know how much to read on. Reads about several kilobytes even when server sends megabytes.
When server sends 3MB and client reads exactly same amount, it takes 30ms. Both in same machine. Trying to read more than server has sent, (even a single byte), raises an exception so TCP really sends exact same amount needed by client.
Weird behavior with Java sockets code running on Java 7 on an AWS machine:
I have a custom protocol to my server wherein we open a socket, then send and receive BSON messages. The test client creates and opens a socket, sends a request, and then camps on the the socket's InputStream, waiting for the response. When a response is received or when the read times out, the next request is sent.
I've discovered that if I touch the socket's InputStream too quickly after I'm done sending the request through the OutputStream, the socket will occasionally block until its read timeout. I've tried both socket.getInputStream().read(...) and socket.getInputStream().available(); both calls cause the problem. If I simply wait 200ms or so after sending, I get nearly 100% successful reads from the server. If, on systems on the same subnet, if I touch the socket immediately after the write (socket.getOutputStream().write(...); socket.getOutputStream().flush()), the socket blocks until its 20-second timeout is reached for between 1% and 7% of all attempts.
Has anyone else seen this behavior? Do you know what's causing it? Do you have a suggestion on how to deal with it? I expect most reads to come back in between 20 and 40ms on a fast network (they mostly do, except the ones which block and time out).
The actual code in use is pretty complex, but here's some relevant snippets:
High-level read/write:
InputStream is = sock.getInputStream();
OutputStream os = sock.getOutputStream();
String req = getRequestData();
String uuid = UUID.randomUUID().toString();
long start = System.currentTimeMillis();
protocolHandler.write(uuid, getUsername(), os, req);
long dt = System.currentTimeMillis() - start;
if (dt < 125l) {
try { Thread.sleep(125-dt); } catch (InterruptedException ex) {}
}
String in = protocolHandler.read(uuid, is, timer, getResponseCount(), getTimeout());
Socket creation:
private Socket newSocket(String socketKey) {
Socket con = null;
try {
SocketAddress sockaddr = new InetSocketAddress(getServer(), getPort());
con = new Socket();
con.setKeepAlive(true);
if (getPropertyAsString(SO_LINGER,"").length() > 0){
con.setSoLinger(true, getSoLinger());
}
con.connect(sockaddr, getConnectTimeout());
if(log.isDebugEnabled()) {
log.debug("Created new connection " + con); //$NON-NLS-1$
}
Client client = new Client(con);
Client.threadIdToClientMap.put(socketKey, client);
} catch (UnknownHostException e) {
log.warn("Unknown host for " + getLabel(), e);//$NON-NLS-1$
e.printStackTrace(System.err);
return null;
} catch (IOException e) {
log.warn("Could not create socket for " + getLabel(), e); //$NON-NLS-1$
e.printStackTrace(System.err);
return null;
}
// (re-)Define connection params - Bug 50977
try {
con.setSoTimeout(getTimeout());
con.setTcpNoDelay(getNoDelay());
} catch (SocketException se) {
log.warn("Could not set timeout or nodelay for " + getLabel(), se); //$NON-NLS-1$
se.printStackTrace(System.err);
}
return con;
}
Socket write:
public void write(String messageId, String playerId, OutputStream os, String hexEncodedBinary) throws IOException {
String messageHexBytes = substituteVariables(hexEncodedBinary);
AbstractMessage messageObject = MessageRewriter.parseRequestData(messageHexBytes);
int seq = MessageRewriter.getSequence(messageHexBytes);
messageObject.setPassthrough(messageId);
byte[] messageBytes = MessageRewriter.serialize(seq, messageObject);
os.write(messageBytes);
os.flush();
}
Socket read:
public String read(String messageId, InputStream socket, LatencyTimer latencyTimer, int requiredResponseCount, int socketTimeoutMillis)
throws ReadException {
String threadName = "thread "+Thread.currentThread().getId();
StringBuilder result = new StringBuilder("passthrough "+messageId+"\n");
int nBytesThisRead = -1;
byte[] buffer=null;
try {
int nResponses = 0;
// As long as we have bytes or need a response, continue to produce messages. Messages we don't use will be cached.
// The socket object throws an exception on timeout (20 seconds-ish) to terminate on "nothing read".
//
// TODO: refactor this abortion so it's readable and understandable
//
while ((! interrupted) && (nResponses < requiredResponseCount || socket.available() > 0)) {
// clear "buffer" to make log messages less confusing (because on 0-byte reads, residual data is logged if we don't do this)
buffer = new byte[0];
// read the size bytes
int totalBytesRead = 0;
byte[] sizeBuffer = new byte[4];
while (totalBytesRead < BYTES_PER_INTEGER) {
try {
nBytesThisRead = socket.read(sizeBuffer, totalBytesRead, BYTES_PER_INTEGER-totalBytesRead);
if (nBytesThisRead > 0) {
latencyTimer.stop()
totalBytesRead += nBytesThisRead;
}
}
//
// this is the timeout we get ~5% of the time if I don't wait ~ 100ms
//
catch (java.net.SocketTimeoutException e) {
log.error(threadName+" timeout waiting for size bytes");
latencyTimer.stop();
return "";
}
}
int messageSize = getLittleEndianInteger(sizeBuffer);
log.debug(threadName+": message size: " + messageSize);
buffer = Arrays.copyOf(sizeBuffer, BYTES_PER_INTEGER+messageSize);
// reset; now read the message body
totalBytesRead = 0;
while (totalBytesRead < messageSize) {
nBytesThisRead = socket.read(buffer, BYTES_PER_INTEGER+totalBytesRead, messageSize-totalBytesRead);
if (nBytesThisRead > 0)
totalBytesRead += nBytesThisRead;
}
if (totalBytesRead != messageSize) {
log.error(String.format("%s abandoning attempt to read %d responses for id %s. Read %d bytes; needed %d.",
threadName, requiredResponseCount, messageId, totalBytesRead, messageSize));
throw new ReadException(
"Unable to read complete Gluon message.", null, result.toString()+toHex(buffer, BYTES_PER_INTEGER + nBytesThisRead));
}
message = MessageRewriter.deserialize(buffer);
String hexString = toHex(buffer, BYTES_PER_INTEGER + messageSize);
String uuid = message.getPassthrough();
if (messageId.equals(uuid)) {
++nResponses;
}
else {
log.debug(String.format("Read: %s message type %s with msgId %s to cache",
threadName, message.getClass().getSimpleName(), uuid));
messageCache.put(uuid, new MessageToClient(message, hexString));
}
// even ignored messages get sent to the verifiers
if (log.isDebugEnabled()) {
log.debug(String.format("Read message for %s (%d bytes): %s", uuid, BYTES_PER_INTEGER + messageSize, hexString));
log.debug(String.format("%s Read: message type %s with msgId %s from socket; still need %d response messages.",
threadName, message.getClass().getSimpleName(), messageId, requiredResponseCount-nResponses));
}
result.append(hexString);
result.append("\n");
}
} catch (IOException e) {
// TODO: clear out the socket? We'd need a new "open new socket" checkbox in the UI, and fail-fast when unchecked.
String msg = result.toString()+"partial:"+toHex(buffer, BYTES_PER_INTEGER + nBytesThisRead);
log.error(threadName+" throwing read exception; read message so far is:\n"+msg,e);
throw new ReadException("Unable to read expected result.", e, msg);
}
return result.toString();
}
I'm new to Java so I need help please. I'm writing an application that will onClick send a String to Server and Server needs to return an image using socket. So my client side is Android and server side is PC - java.
I think that my server side is ok (because he prints out all the system.out.print commands) but my client side is not good. Please tell my where is my mistake? Thanks!
Here is code of my Server (PC) side (socket is delivered thru function parameter):
try {
dataInputStream = new DataInputStream(socket.getInputStream());
poruka = "" + dataInputStream.readUTF();
System.out.print(poruka);
int bytecount = 2048;
byte[] buf = new byte[bytecount];
OutputStream OUT = socket.getOutputStream();
BufferedOutputStream BuffOUT = new BufferedOutputStream(OUT, bytecount);
FileInputStream in = new FileInputStream("screenShot.jpg");
int i = 0;
while ((i = in.read(buf, 0, bytecount)) != -1) {
BuffOUT.write(buf, 0, i);
System.out.print("check" + buf[0]);
BuffOUT.flush();
}
in.close();
BuffOUT.close();
System.out.print("over");
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
socket.close();
dataInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
and here is my Client (Android) side:
Socket socket = null;
DataOutputStream dataOutputStream = null;
try {
socket = new Socket(IPadresa, 8888);
dataOutputStream = new DataOutputStream(socket.getOutputStream());
slanje = "hy string";
dataOutputStream.writeUTF(slanje);
FileOutputStream outToFile = new FileOutputStream("slika.jpg");
int bytecount = 2048;
byte[] buf = new byte[bytecount];
InputStream IN = socket.getInputStream();
BufferedInputStream BuffIN = new BufferedInputStream(IN, bytecount)
int i = 0;
int filelength = 0;
while((i = BuffIN.read(buf, 0, bytecount)) != -1) {
filelength += i;
outToFile.write(buf, 0, i);
outToFile.flush();
}
IN.close();
BuffIN.close();
dataOutputStream.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
MORE INFORMATIONS:
In server side I can see String that is send from Client. And I have that System.out.print("over"); command printed every time I send String to Server. Also I have System.out.print("check" + buf[0]); printed out from Server many times. So that is why I think that there is something wrong with Client side.
And my Client side doesn't throw any Exceptions... but I noticed that Client side never passed the while loop. It get stuck there.
I don't know what you mean by "my client side is not good", and I can't see any obvious errors that would stop it working entirely. If you could tell us what happens, that would help.
Meanwhile there are a couple of things wrong with the code you have presented:
You are violating industry accepted coding standards with names such as "BuffIn", "IN", "IPaddresa" and so on. All variable names in Java must start with a lowercase letter.
If you do this in private code that is your business. But if you are going to show your Java code to other people, you should conform to the standards. (And posting your code on SO is showing it to other people ...)
Since you are always trying to read a whole buffer's worth of data, replace in.read(buf, 0, bytecount) with in.read(buf).
There is no value in using a BufferedInputStream or BufferedOutputStream if you are only going to do large read or write calls on it. Even more so if you tell the stream to use the same size buffer as your the byte[] you are reading / writing.
Both your client and server side code could leak file descriptors. On the server-side it could leak in. On the client side, any or all of the streams' file descriptors could leak.
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.
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.