Client side:
out = new DataOutputStream(connection.getOutputStream());
String process;
System.out.println("Connecting to server on "+ host + " port " + port +" at " + timestamp);
process = "Connection: "+host + ","+port+","+timestamp;
System.out.println("client len " + process.length());
out.write(process.length());
Prints:
Client len 55
Server side:
in = new DataInputStream(connection.getInputStream());
while (true) {
int len = in.readInt();
System.out.println("Length of pkt: "+len);
Prints: Length of pkt: 927166318
What's going on here? I tried writing 0 and it printed 3621743 on the server side. I checked some other sites and a few people had problems with other streams. I read about the issues arising with big vs little endianness, but I am not sure what the problem is here since I am using the data*streams that should work fine with each other.
If you call readInt() on one side, you should call writeInt(int) on the other. Change this
out.write(process.length());
to
out.writeInt(process.length());
From the Javadoc for write(int),
Writes the specified byte (the low eight bits of the argument b) to the underlying output stream.
Use out.writeInt(process.length()); instead of out.write(...); since you read an Integer from the stream afterwards.
Related
I'm trying to receive a string from a device using this code:
byte[] buf = new byte[4];
int read = inFromDevice.read(buf);
Logger.getLogger(Utill.class.getName() + " DEBUG_ERR01").log(Level.INFO, "Bytes read: {0}", read);
int msgLength = ByteBuffer.wrap(buf).getInt();
Logger.getLogger(Utill.class.getName() + " DEBUG_ERR01").log(Level.INFO, "Message length: {0}", msgLength);
Reader r = new InputStreamReader(inFromDevice);
char[] cb = new char[msgLength];
int actualCharsRead = r.read(cb);
Logger.getLogger(Utill.class.getName() + " DEBUG_ERR01").log(Level.INFO, "Actual chars read: {0} char array length: {1}", new Object[]{actualCharsRead, cb.length});
String msgText = String.valueOf(cb, 0, cb.length);
Logger.getLogger(Utill.class.getName() + "Messages Loggining recieve: ").log(Level.INFO, msgText);
return msgText;
the inFromDevice is and InputStream acquired from an accepted ServerSocket.
The code is working and returning messages most of the time, but some times I get messages smaller than msgLength (which is wrong according to the protocol)
An example from the log is Actual chars read: 1020 char array length: 1391
I think the problem is external due to a network problem or device is having an issue, but I need some expert insight on this. are there any known problems in Java that may cause this?
An InputStreamReader will only block until it can read one character into the buffer, or detect EOF. There is no guarantee that the buffer will be filled.
If your protocol indicates the length of the string being sent, the receiver needs to loop, tracking the number of characters remaining, until all have been read.
I'm trying to open a socket, send a message (requesting the HEAD) and get the response from server.
My code is similar to a lot of other codes I'm looking for, here in SO,or googling.
Here is:
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
public class ClientTCPSocket {
public static final int PORT = 80;
public static void main(String argv[]) {
BufferedReader inputKeyboard = new BufferedReader(new InputStreamReader(System.in));
Socket socket;
InetAddress ipAddress;
String host = "";
String head = "";
String input_message = "";
try {
System.out.println("Host to connect?");
host = inputKeyboard.readLine();
head = "HEAD / HTTP/1.1\r\n"
+ "Host: "+ host +"\r\n"
+ "\r";
ipAddress = InetAddress.getByName(host);
socket = new Socket(ipAddress, PORT);
DataOutputStream ouput = new DataOutputStream(socket.getOutputStream());
System.out.println("\nSending info...");
System.out.println(head);
System.out.println("===============================");
ouput.writeUTF(head);
BufferedReader inputFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while ((input_message = inputFromServer.readLine()) != null) {
System.out.println(input_message);
}
System.out.println("===============================");
socket.close();
inputFromServer.close();
} catch (IOException e) {
System.out.println("Alguna cosa ha anat malament");
e.printStackTrace();
}
}
}
(As I read in wiki: https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Message_format I need to put the carriage and line feed. I said that because I tested only using "\n")
But after all, If I call for example "localhost" (I got a basic xampp opened in the mac) or even "google.com", I'm getting Error 400, BAD Request, when is supposed I had to receive code 200.
I don't know what I'm forgetting or which combination of info I have to send .
Your problems are caused by multiple reasons:
Usage of writeUTF
From the documentation of ouput.writeUTF(head);
Writes a string to the underlying output stream using modified UTF-8 encoding in a machine-independent manner.
First, two bytes are written to the output stream as if by the writeShort method giving the number of bytes to follow. This value is the number of bytes actually written out, not the length of the string. Following the length, each character of the string is output, in sequence, using the modified UTF-8 encoding for the character. If no exception is thrown, the counter written is incremented by the total number of bytes written to the output stream. This will be at least two plus the length of str, and at most two plus thrice the length of str.
Since these 2 bytes are prefixed to your string, it is causing an invalid HTTP request
You should manually convert your string to bytes, and send that, or use an InputStreamWriter
ouput.write(head.getBytes(StandardCharsets.UTF_8));
Missing trailing \n
Your final newline in the message is incomplete
head = "HEAD / HTTP/1.1\r\n"
+ "Host: "+ host +"\r\n"
+ "\r";
should be
head = "HEAD / HTTP/1.1\r\n"
+ "Host: "+ host +"\r\n"
+ "\r\n";
Assuming the end of the stream is reached
In HTTP 1.1, all connections are persistent by default, this means that the server will keep the connection open for a while after a request.
WHile you don't see the effect at the moment (because the malformed request, the server assumes its HTTP 1.0), this is a problem if you start sending valid requests.
Since this means that your program never breaks out of the for loop, we need to either detect the end of a request (hard!), or be a little less efficient and say to the server that we want to close our connection:
head = "HEAD / HTTP/1.1\r\n"
+ "Host: "+ host +"\r\n"
+ "Connection: close\r\n"
+ "\r\n";
Missing user agent
While this isn't a violation of the protocol persee, some server may require the user agent header these days, and reject all connections without this header.
This is really easy.
head = "HEAD / HTTP/1.1\r\n"
+ "Host: "+ host +"\r\n"
+ "user-agent: Test program made by https://stackoverflow.com/users/1282166/shudy\r\n"
+ "\r\n";
I am trying to send two byte arrays over a Java socket. I have captured the data via wireshark and it shows that the first byte array sends; the second, however, doesn't send at all.
I am using Linux Mint and Oracle's JRE (not OpenJDK).
byte[] packet_one = new byte[] {(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x50};
byte[] packet_two = new byte[] {(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x78};
Socket sck;
DataInputStream dis;
DataOutputStream dos;
try {
sck = new Socket(IP_ADDRESS,PORT);
dis = new DataInputStream(sck.getInputStream());
dos = new DataOutputStream(sck.getOutputStream());
int recv_header = dis.ReadInt(); // This receives the correct response.
dos.write(packet_one); // Sends fine.
dos.write(packet_two); //Does not send.
int data_length = dis.readInt(); // No more data received.
}catch(Exception e) {
System.out.println("Error: " + e.getMessage());
}
So, dos.write(packet_one) works (confirmed by wireshark). Writing packet_two doesn't work. The data_length returns 0 since I don't receive anymore data either. No errors or exceptions get caught.
I have also tried using dos.flush(), but it doesn't make a difference.
Any ideas on why this may be the case?
Maybe you're exiting the program before there's time to send the buffered bytes?
Perhaps if you add something like:
for (;;) {
final byte x = dis.readByte();
System.out.println("got byte: " + (x & 0xFF));
}
the program won't exit, and you'll also see if there are more bytes that the server sent back. Might offer clues.
And, in case you don't know, readInt() reads for bytes and returns an int made from those bytes, which is 0 if all the for bytes read are zero. So your comment 'No more data received.' feels a bit ambiguous.
You could also try inserting a
sck.setTcpNoDelay(true);
after creating the socket. Writes should then go on the network immediately. I think.
Hope this helps.
I've been playing around with transferring data between a test client (written in Java) and a server (written in C#/.NET).
I tried TCP clients and servers, but there has been and current is a problem flushing the stream. I realize flush doesn't always flush the stream, so I'm wondering if there is any way to flush/send a stream without .flush() or in a more reliable way?
Currently, the important part of the client looks like this (message is a string, serverSocket is a Socket object):
OutputStream output = serverSocket.getOutputStream();
byte[] buffer = message.getBytes();
int length = buffer.length;
output.write(ByteBuffer.allocate(4).putInt(length).array());
output.write(buffer);
output.flush();
and the server looks like this:
NetworkStream stream = client.GetStream ();
byte[] sizeBuffer = new byte[4];
int read = stream.Read (sizeBuffer, 0, 4);
int size = BitConverter.ToInt32 (sizeBuffer, 0);
Databaser.log ("recieved byte message denoting size: " + size);
byte[] messageBuffer = new byte[size];
read = stream.Read (messageBuffer, 0, size);
string result = BitConverter.ToString (messageBuffer);
Databaser.log ("\tmessage is as follows: '" + result + "'");
Where, if it's not evident from the code, the client sends 4 bytes, which are combined into a 32 bit integer which is the length of the message. Then I read in the message based on that length and have build in converters translate it into a string.
As I said, I'm wondering how to flush the connection? I know this code isn't perfect, but I can change it back to when I used TCP and UTF exclusive string messaging over the network, but either way, the connection doesn't send anything from the client until the client shuts down or closes the connection.
Maybe the problem is in the byte order. I have an application which send from a tablet (java) to a C# application (Windows Intel), I used similar to what you've done, except in the following
ByteBuffer iLength = ByteBuffer.allocate(4);
iLength.order(ByteOrder.LITTLE_ENDIAN);
iLength.putInt(length);
output.write(iLength.array(), 0, 4);
output.write(buffer);
output.flush();
Java uses BIG-ENDIAN and Intel uses LITTLE-ENDIAN bytes order.
I was thinking about how you would read how much data you send over a Socket. For example if I made a Chat Application and then wanted to find out how much a message would take (in kilobytes or bytes), how would I measure this?
I send a message like "Hello, world!". How do I measure the amount of bandwidth that would take to send?
I know there are programs to monitor how much data is sent and received over the wire and all that, but I wanted to try and do this myself to learn some.
Wrap the socket's output stream in a CountingOutputStream:
CountingOutputStream cos = new CountingOutputStream(socket.getOutputStream());
cos.write(...);
System.out.println("wrote " + cos.getByteCount() + " bytes");
If you send raw string with no header (protocol)
For the strings you have
String hello = "Hello World";
hello.getBytes().length //size of the message
For showing progress to user when sending files you can do this
Socket s = new Socket();
//connect to the client, etc...
//supose you have 5 MB File
FileInputStream f = new FileInputStream( myLocalFile );
//declare a variable
int bytesSent = 0;
int c;
while( (c = f.read()) != -1) {
s.getOutputStream().write(c);
bytesSent++; //One more byte sent!
notifyGuiTotalBytesSent(bytesSent);
}
well, thats just a very simple implementation not using a buffer to read and send the data just for you get the idea.
the method nitify.... would show in the GUI thread (not this one) the bytesSent value