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.
Related
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.
How can i send a buffer of data whose length is 1 MB over socket in java.
What exactly i am doing is that i want to calculate upload speed of network.For that i want to send 1 MB data to server which i have written in C.
In C to receive and send data we have functions like send and recv through which we can send the desired number of bytes by passing the number of bytes to be sent.
send(connfd , client_message , `Bytes to send`, 0);
but in java i am able to send only 1 byte at a time using
int buffer[] = new int[1048576];
PrintWriter output1 = new PrintWriter(socket.getOutputStream(), true);
output1.print(buffer[1]);
so to send multiple bytes i need to call above function again and again. Is there any way in which i can pass whole buffer of 1048576 in on go.
Your PrintWriter has a print(char[] s) method (see doc). So you could instead create a new char array with the corresponding size (note: a char in Java is 2 byte long) and send that char array using that method.
But there is a better option: A look into the doc tells us we get an OutputStream from our socket. We could wrap that into a BufferedOutputStream, like this:
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte buffer[] = new byte[1024*1024];
bos.write(buffer, 0, buffer.length);
And then use bos.write(byte[], int, int) to directly send a byte array, which probably would be the most direct way to achieve what you want.
I want to connect Android Device to external device via Socket. Socket Connect to external device successfully.
Now if any data require from external device then send request of byte packet data to socket below order. if external device receive data correct then send byte data in response.
Parameters : methodname(1 byte), payloadlength(2 byte), payload(2 byte).
Now My Code is...
Socket socket = new Socket("local exteranl device ip", 5000);
if(socket.isConnected()) {
int methodname = 5;
int payload = 2151;
int payloadLength = 2;
ByteBuffer buffer = ByteBuffer.allocate(3 + payloadLength); // 3 = for method name + length
buffer.order(ByteOrder.BIG_ENDIAN); // Just to be explicit
buffer.put((byte) methodname);
buffer.putShort((short) payloadLength);
buffer.putShort((short) payload);
buffer.rewind();
byte[] result = new byte[buffer.capacity()]; // Could also use result = buffer.array();
buffer.get(result);
DataOutputStream classOUTstream = new DataOutputStream(socket.getOutputStream());
// socket is already connected
classOUTstream.write(result);
classOUTstream.flush();
InputStream stream = socket.getInputStream();
byte[] data = new byte[100];
int count = stream.read(data);
}
Above Code is Android, i knowing only basic concept of java. i am getting -1 result in count.
can any one please suggest me or tell me my mistake?
You're doing this the hard way. Get rid of the ByteBuffer altogether and use all the methods of DataOutputStream. They are all big-endian. I can't see any mistake but clearly you must be sending something the peer didn't understand so he is closing the connection instead of sending a reply.
Note: Socket.isConnected() cannot possibly be false at the point you're testing it.
I'm developing a server-client application.
The server is done in Java (PC) and the client in Java. (Android)
I'm having trouble with the following implementation:
Server grabs bitmap -> raw bytes -> TCP -> Client (Async Streams
Now the byte array is delivered in multiple packets of different lengths in the client. So to handle this properly, I should use the prefix method.
To use prefix mode you need to send the length of the message in bytes
as four bytes and then the message
My code
public void sendScreenshot(byte[] buffer) throws IOException {
OutputStream os = socket.getOutputStream();
os.write(buffer.length + 1);
os.write((byte) 0);
os.write(buffer, 0, buffer.length);
os.flush();
}
In VB.net, this is achieved in the following code:
Private Sub dat(ByVal dat As String)
Dim nstream As NetworkStream = sock.GetStream()
Dim bit As Byte() = System.Text.Encoding.UTF8.GetBytes(dat)
Dim bw As New BinaryWriter(sock.GetStream())
bw.Write(bit.Length + 1)
bw.Write((byte)command)
bw.Write(bit, 0, bit.length)
End Sub
Any help implementing it in Java is welcome?
Use a DataOutputStream:
DataOutputStream out = new DataOutputStream(os);
out.writeInt(buffer.length + 1);
// This writes a single byte
out.write(0);
out.write(buffer);
out.flush();
The .writeInt() here comes from this part of the text you quoted:
you need to send the length of the message in bytes as four bytes
which means an int. Note that this will write the int in network order. While this is unspecified in your extract, I suppose this is what is expected.
Similarly, on the receiving end, you can use a DataInputStream, read the length as an int and then the payload.
I have this TCP server running Because UDP server was able to accept large packets but ISP blocks my UDP packets even i have Public IP and Static services. But now decided to change it to TCP but i have a large stack now to replace with UDP to TCP.
Here is the server which is running but it does not at once receive a large packet, how can i increase it to unlimited or maximum size or etc?
1) Is there any way with this?
public void run()
{
while(true)
{
byte[] buf=new byte[5024]; <<< not helping!!
int bytes_read = 0;
try {
bytes_read = sockInput.read(buf, 0, buf.length);
String data = null;
data = new String(buf, 0, bytes_read);
System.out.println("[TCP]: incomeing data: " + bytes_read + " bytes, data=" +data);
}
}
2) Is there any way with this?
public TCPHandler(Socket sock) throws IOException
{
sock.setReceiveBufferSize(10*1024 +1024); //<<<<< not helping !!!
sock.setSendBufferSize(10*1024+1024);
this.sock = sock;
sockInput = sock.getInputStream();
sockOutput = sock.getOutputStream();
this.myThread = new Thread(this);
}
None is allowing me to handle large so that i can switch from UDP to TCP. Any ideas!!
TCP and UDP are different. TCP is not a packet-based protocol, it is a stream based protocol. Your data will arrive in order, and un-corrupted, but it will not necessarily all arrive at once.
What you should do is prefix each set 'packet' with a length. When you receive data, first read the length value, and then continue reading chunks from the socket until you have the amount of data required.
You shouldn't care how TCP splits your messages into packets and how many times you must read to get a full message. Just read until the end of the message has been reached, and then return all the bytes of the message.
Knowing when the message has been read completely depends on your protocol. You could choose to send only one message per connection, or you could send the length of the message before the message, or use some marker byte.
Note that you shouldn't use new String(byte[]) without specifying an encoding (and use the same when calling String.getBytes()), especially if you transfer from one machine to another, since both machines could have a different default encoding.
The trouble you're having is how InputStreams work. When you call read(buf,offset,length) it doesn't always read length bytes everytime. It simply reads what is available() on the InputStream, and returns the number of bytes it read. So you need to continue to call read until you've actually read length bytes.
int len = 0;
int expectedLength = sockInput.readInt();
byte[] buf = new byte[ expectedLength ];
while( len != buf.length ) {
len += sockInput.read( buf, len, buf.length );
}
// now you have a buffer with expectedLength data in it.
You can also look at using DataInputStream.readFully() by wrapping your
DataInputStream ds = new DataInputStream( sock.getInputStream() );
ds.readFully( buf, 0, buf.length );
http://docs.oracle.com/javase/6/docs/api/java/io/DataInputStream.html
But if you're really just after a String you should do this:
Reader reader = new InputStreamReader( sockInput.getInputStream(), "UTF-8" );
Same rules for read( char[], offset, length ) as read( byte[], offset, length )
A TCP is a stream of bytes you can get a portion of, one or more messages is a single read.
With UDP packets of more than 532 bytes, the packet can be broken up, so you have the same potential problem.
A simple way to encode message is to send the length first.
final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
final DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
public void writeMessage(String text) {
out.writeUTF(text);
}
public String readMessage() {
return in.readUTF();
}
read/write UTF sends the length first and followed by the content