I am currently implementing a game server manager for the RCON server protocol. I'm opening a connection to the server via a socket:
this.socket = new Socket();
this.socket.connect(new InetSocketAddress(this.getAddress(), this.getPort()), 3000);
The connection works fine, I can communicate with the server and receive the responses. No problem there. My problem is that when I am debugging the communication process and i take to long getting from the request to the read on the input stream, I am getting a message "Keep Alive". This is the code for request and response:
send:
Rcon rcon = new Rcon();
byte[] data = rcon.constructPackage(this.getPort(), pRequestType, pPayload);
OutputStream out = this.socket.getOutputStream();
out.write(data);
out.flush();
receive:
InputStream in = this.socket.getInputStream();
byte[] header = new byte[3*4];
in.read(header);
ByteBuffer buffer = ByteBuffer.wrap(header);
buffer.order(ByteOrder.LITTLE_ENDIAN);
int length = buffer.getInt();
int id = buffer.getInt();
int type = buffer.getInt();
int payloadLength = length - (2*4) - 2;
byte[] payload = new byte[payloadLength];
DataInputStream dis = new DataInputStream(in);
dis.readFully(payload);
dis.read(new byte[2]);
payloadString = new String(payload);
I have searched for this as Java and RCON related but I did not find a single clue where this is coming from. I'm guessing this is an RCON related effect, since I have to interpret the package which is received from the RCON server and split its contents to get to the actual payload. After this is done, the payload string contains "Keep Alive".
Related
I need to sent a packet to a server using socket from my android application. I only know a packet layout:
Packet ID 4 bytes | Packet length 4 bytes(minus len + ID) | payload (protobuf message)
The whole stuff about TLSv1.2 connection and self-signed certificate works well. For example, I need to send authentication packet - LoginRequest and server will response with LoginResponse if the packet was sent successfully. What I am trying do to is connect to a server inside AsyncTask class, write data and receive response, but obviously I am doing it wrong because I got no response. The code for writing and reading a message:
LoginRequest protobuf message:
Protos.LoginRequest loginRequest = Protos.LoginRequest.newBuilder()
.setUsername(mailAddress)
.setPassword(pass).build();
And the code(inside doInBackground() method):
//TLSSocketFactory is custom SSLSocketFactory class for forcing TLSv1.2 on devices > 16 & < 20
socket = tlsSocketFactory.createSocket("airwave1.exurion.com", 2559);
byte[] payload = loginRequest.toByteArray();
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
InputStream inStream = socket.getInputStream();
out.writeInt(10); //ID of the packet
out.writeInt(payload.length);
out.write(payload);
out.flush();
byte[] data = new byte[100];
int count = inStream.read(data);
out.close();
inStream.close();
socket.close();
As I said I got no response, Sometimes I also get an SSLException while reading the message:
javax.net.ssl.SSLException: Read error: ssl=0xb3a28580: I/O error during system call, Connection timed out
Has anyone an idea how to solve this?
//UPDATED
I figured out that the byte order needs to be in LITTLE_ENDIAN, so I tried to use ByteBuffer:
//based on previous packet layout (4 bytes for ID, 4 bytes for payload length, and payload) - is it ByteBuffer.allocate() fine?
ByteBuffer buffer = ByteBuffer.allocate(8 + payload.length);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.putInt(LoginPacketType.LOGIN_REQUEST.getId());
buffer.putInt(payload.length);
buffer.put(payload);
buffer.rewind();
byte[] result = new byte[buffer.capacity()]; // Could also use result = buffer.array();
buffer.get(result);
out.write(result);
But now I am getting OOM exception:
Failed to allocate a 184549388 byte allocation with 16777216 free bytes and 155MB until OOM
Details about that:
After writing to an DataOutputStream, I make:
buffer.clear()
out.flush();
//code for reading from InputStream
And now, in my log appears this message several times:
Starting a blocking GC Alloc
and than throws OOM exception.
The problem was with LITTLE_ENDIAN and BIG_ENDIAN order. Servers sends response in LITTLE_ENDIAN order so I rewrite your answer a bit:
int type = inStream.readInt();
type = Integer.reverseBytes(type);
int length = inStream.readInt();
length = Integer.reverseBytes(length);
if (length > 0) {
byte[] data = new byte[length];
inStream.readFully(data);
Protos.LoginResponse response = Protos.LoginResponse.parseFrom(data);
}
Thanks for the hint.
You're writing a packet type and length and payload, but you're only reading a payload. You're also assuming that read() fills the buffer.
int type = din.readInt();
int length = din.readInt();
byte[] data = new byte[length];
din.readyFully(data);
I know TCP is better to send file but I have a homework about sending file via udp protocol . Is there any code example in C# or Java about sending file?
I have server-client example to send and recieve message. I tried to send the file using the same way but could not succeed. I may need an algorithm to divide the file small parts and send them via datagram, and I have an idea to put "md5" of the part as header of the array to check if the packet is lost or not.
Here is my try , my server side in java;
// 1. creating a server socket, parameter is local port number
sock = new DatagramSocket(7777);
// buffer to receive incoming data
byte[] buffer = new byte[65536];
DatagramPacket incoming = new DatagramPacket(buffer, buffer.length);
byte []bigByteArray=new byte[1024*1024*1024*1024];
// 2. Wait for an incoming data
echo("Server socket created. Waiting for incoming data...");
ByteBuffer target = ByteBuffer.wrap(bigByteArray);
// communication loop
while(true)
{
try
{
sock.receive(incoming);
String s = new String(incoming.getData());
if(s=="finish") break;
target.put(incoming.getData());
}
catch(Exception e)
{
}
}
fos.write(bigByteArray);
fos.close();echo("RECIEVED");
and my client side;
String s;
Path path=Paths.get("C:\\Users\\Toshiba\\Desktop\\aa.txt");
byte[] data = Files.readAllBytes(path);
try
{
sock = new DatagramSocket();
InetAddress host = InetAddress.getByName("localhost");
//take input and send the packet
byte [] part;
for (int i = -1; i < data.length; i=i+100)
{
if(sock.isConnected())
{
part=Arrays.copyOfRange(data,i+1,i+100 );
}
else i=i-100;
}
byte [] f="finish".getBytes();
DatagramPacket finalpac = new DatagramPacket(f ,f.length , host , port);
sock.send(finalpac);
}
Thank you in advance.
Several issues:
The following isn't correct:
sock.receive(incoming);
String s = new String(incoming.getData());
The final line should be
String s = new String(incoming.getData(), incoming.getOffset(), incoming.getLength());
and if you aren't receiving text you shouldn't be converting the data to a String at all.
Remove the sock.isConnected() test. DatagramSockets are not usually connected, and you certainly haven't connected this one.
The loop in which this is embedded does nothing useful. You are only sending the word "finish".
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 am trying to write a simple program about UDP Connections to learn about them. I have implemented some basic things but when I try to send and get back what I sent but I face some problems like,
When I do this ;
send a string
"asd" to server I get back asdxxxxxxxxxx
and when I try to print What I get in the server I get [B#5f186fab
How can I solve this problem ?
To be more clear I am sending you a few lines of code ,
In client;
Scanner in = new Scanner(System.in);
String result = in.nextLine();
// send request
byte[] buf = new byte[1000];
String read = result;
InetAddress address = InetAddress.getByName("localhost");
DatagramPacket packet = new DatagramPacket(result.getBytes(), result.getBytes().length, address, 4445);
socket.send(packet);
// get response
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
// display response
String received = new String(packet.getData(), 0, packet.getLength());
System.out.println("Quote of the Moment: " + received);
In server ;
byte[] buf = new byte[1000];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
byte[] received = packet.getData();
System.out.println(received.toString());
// figure out response
// send the response to the client at "address" and "port"
InetAddress address = packet.getAddress();
int port = packet.getPort();
packet = new DatagramPacket(received, received.length, address, port);
socket.send(packet);
Thank you all
EDIT 1 I think I have problems with my buffer but I dont know how to solve .
You can use
System.out.println(Arrays.toString(received));
but what you probably want is
System.out.println(new String(received, o, lengthRead, "UTF-8"));
Have you fixed this?
Otherwise, what I've found is that if you declare a receiving byte[] buf with a capacity that's greater than the length string you're actually receiving, you'll end up with the rest of the buffer full of unwanted bytes.
Eg. if you declare byte[] received = new byte[1000]; but only receive a string of 4 bytes, you'll end up with 996 unwanted bytes.
One quick way around this is to do something like
byte[] received = packet.getData();
System.out.println(received.toString().trim());
trim() did the trick for me. Hope that helps you!
Hey everyone, I'm having a bit of a problem with UDP and Datagrams. I'm supposed to make a server that will get a request from the client to send a file in the same directory. The UDP Server will then get this file (a video), put it into a datagram and send it. I think I know how to do it, but I can't put the file in the datagram. I'm putting it in Binary form, so keep that in mind.
Here's my code so far:
edit: This is the server by the way, and I keep having trouble with BufferedInputReader and OutputReader, so keep that in mind :)
Scanner inFromUser = new Scanner(System.in);
int port = 12345;
DatagramSocket server = new DatagramSocket(port);
// Read name of file supplied by client (must be a line of text):
Scanner in = new Scanner(new DataInputStream(server.getInputStream()));
String filename = in.nextLine();
DatagramSocket request = server.accept();
// Create buffer, then we're ready to go:
// Puts file into binary form
BufferedInputStream inbinary =
new BufferedInputStream(new FileInputStream("poop.txt"));
// Outputs the binary form
BufferedOutputStream outbinary =
new BufferedOutputStream(request.getOutputStream());
int numbytes;
int countblocks = 0;
int countbytes = 0;
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length, port);
server.receive(packet);
while ((numbytes = inbinary.read(buf,0,1024)) >= 0)
{
// receive packet from client, telling it to send the video file
server.receive(packet);
InetAddress address = packet.getAddress();
packet = new DatagramPacket(buf, buf.length, address, port);
server.send(packet);
countblocks++; // keep statistics on file size
countbytes += numbytes;
outbinary.write(buf,0,numbytes); // write buffer to socket
}
outbinary.flush(); // FLUSH THE BUFFER
server.close(); // done with the socket
System.out.println(countblocks + " were read; " + countbytes + " bytes");
}
}
I haven't done datagrams in a while, but I'm pretty sure the accept() call is wrong. That's for TCP servers.
I'd recommend cribbing from Sun's excellent tutorial: http://java.sun.com/docs/books/tutorial/networking/datagrams/clientServer.html