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.
Related
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".
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".
Local on Linux. It's about 10 seconds for a 20k message. My guess is my Java is bad and Python is fine.
py client:
def scan(self, msg):
try:
print 'begin scan'
HOST = 'localhost'
PORT = 33000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT));
s.sendall(msg)
data = s.recv(1024)
s.close()
print 'Received', repr(data)
except Exception, e:
print "error: " + str(e)
Java server:
ServerSocket service = new ServerSocket(33000);
while(true) {
debug("Begin waiting for connection");
//this spins
Socket connection = service.accept();
debug("Connection received from " + connection.getInetAddress().getHostName());
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
BufferedInputStream in = new BufferedInputStream(connection.getInputStream());
ScanResultsHeader results = new ScanResultsHeader();
Scanner scanner = new Scanner();
results = scanner.scan("scannerfake#gmail.com", "123", in);
and
public ScanResultsHeader scan (String userEmail,
String imapRetrievalId,
BufferedInputStream mimeEmail)
throws IOException, FileNotFoundException, MimeException, ScannerException {
//how fast would it be to just slurp up stream?
debug("slurp!");
String slurp = IOUtils.toString(mimeEmail);
debug("slurped " + slurp.length() + " characters");
slurp = slurp.toLowerCase();
debug("lc'ed it");
//...
My guess is I'm juggling the input streams wrong. One catch is the "BufferedInputStream mimeEmail" signature is required by the library API scan is using, so I'll need to get to that form eventually. But I noticed the simple act of slurping up a string takes ludicrously long so I'm already doing something incorrect.
Revising my answer....
If you are reading efficiently, and it appears you are, it will only be taking a lot time because either
You are creating a new connection every time you send a message which can be very expensive.
You are not sending the data as fast as you think.
The message is very large (unlikely but it could be)
There are plenty of examples on how to do this and a good library you can use is IOUtils which makes it simpler.
You should be able to send about 200K/s messages over a single socket in Java.
If you have a sends X bytes protocol using Big Endian you can do this.
DataInputStream dis = new DataInputStream( ...
int len = dis.readInt();
byte[] bytes = new byte[len];
dis.readFully(bytes);
String text = new String(bytes, "UTF-8");
Original problem was that the client isn't sending an end-of-input so the "slurp" operation keeps waiting for more stuff to cross the connection.
Solution was to implement an application-layer protocol to send the size of the message in advance, then stop listening for more message after that many bytes. I would have preferred a standard library -- something like, FiniteInputStream extends BufferedInputStream and takes a size as an argument, but wrote my own.
following is my client side code , that retrieves text from server and prints.
Socket socket = new Socket(ip, port);
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
String string = "Hello!\n";
byte buffer[] = string.getBytes();
out.write(buffer);
while ((character = in.read()) != -1){
System.out.print((char) character);
}
I am getting the the correct values from the server , but it is happening again and again , how can i find out the length of the value sent.
-1 denotes the end of the stream, and is received when the connection is closed. If you want to keep the connection open and send multiple messages, you need some sort of protocol (kind of like agreement between both ends) that tells where the message ends. The are many ways to do this, but in your example you're writing a line terminator (\n) to the end of the message, so you could check for that at the other end. Another way is to write the amount of bytes you're about to send before the actual message contents.