Send DHT queries to "router.bittorrent.com" response garbled text - java

I read the DHT Protocol in bep_0005 page.
But when I send a ping query or a find_node query, the server response a garbled text (both of router.bittorrent.com:6881 or dht.transmissionbt.com:6881)
Here is the Java source code bellow
public String ping(final String id) {
System.out.println("Start ping:" + id);
Bencode bencode = new Bencode();
byte[] encoded = bencode.encode(new HashMap<Object, Object>() {
private static final long serialVersionUID = 4225164001818744013L;
{
put("t", "tr");
put("y", "q");
put("q", "ping");
put("a", new HashMap<Object, Object>() {
private static final long serialVersionUID = -6092073963971093460L;
{
put("id", id);
}
});
}
});
byte[] result = client.send(new String(encoded, bencode.getCharset()));
Map<String, Object> dict = bencode.decode(result, Type.DICTIONARY);
System.out.println("Bdecoded Data:" + dict);
return "";
}
Send Packets
ping Query = {"t":"aa", "y":"q", "q":"ping", "a":{"id":"abcdefghij0123456789"}}
bencoded = d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t2:aa1:y1:qe
Acrodding to the bep_0005 protocol the response with be like:
Response = {"t":"aa", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}}
bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re
But my response is:
Response = {ip=��P���, r={id=2�NisQ�J�)ͺ����F|�g}, t=tr, y=r}
bencoded = d2:ip6:��P���1:rd2:id20:2�NisQ�J�)ͺ����F|�ge1:t2:tr1:y1:re
Send udp part Java code is:
public byte[] send(String sendData) {
DatagramSocket client;
try {
client = new DatagramSocket();
client.setSoTimeout(5000);
byte[] sendBuffer;
sendBuffer = sendData.getBytes();
InetAddress addr = InetAddress.getByName("router.bittorrent.com");
int port = 6881;
DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length, addr, port);
client.send(sendPacket);
byte[] receiveBuf = new byte[512];
DatagramPacket receivePacket = new DatagramPacket(receiveBuf, receiveBuf.length);
client.receive(receivePacket);
System.out.println("Client Source Data:" + Arrays.toString(receivePacket.getData()));
String receiveData = new String(receivePacket.getData(), "UTF-8");
System.out.println("Client String Data:" + receiveData);
client.close();
return receivePacket.getData();
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
read the response in UTF-8 , but the iso-8859-1 is also a garbled text.
who can help me,thanks!

the server response a garbled text
No, the response is bencoded and contains raw binary data.
It CAN NOT be treated as text.
In BEP5, to make the raw binary node_id in the examples printable,
it has cleverly been chosen to consist of only alphanumeric characters.
See:
Bittorrent KRPC - Why are node ID's half the size of an info_hash and use every character a-z?
The ip key is a extension explained in: BEP42 - DHT Security extension
The received response is fully valid.
TODO: Working Java code

Map<String, Object> dict = bencode.decode(result, Type.DICTIONARY);
This gives you the decoded root dictionary of the message as Map. Within that you should find the r dictionary as another map and with in that map the id value. What type the id has will depend on the bedecoding library you are using.
If it is ByteBuffer or byte[] then you should have 20 bytes that you can hexencode (to 40 characters) if you need it to be human-readable. The DHT protocol deals in raw hashes, not hex values.
If it is a String then you will have to convert the string back into byte[] before hex-encoding it. That is only possible when the bdecoder used ISO 8859-1 to decode because that charset is roundtrip-safe while utf-8 is not for arbitrary byte sequences.

Related

Read and write on single socket in java

I have a socket server which accepts only one client socket connection. It will remember the connection and send response on the same. If client opens one more connection to the server with same host and port, then server will accept it but send response on last remembered socket connection. I don't know how server is able to do it as it is not in my control.
Below is code i tried. In my code, I am first creating Socket connection with server and storing it in Spring application context. For every request, I am getting it and using Input and Output Stream.
I am able to send one request and receive one response. But when i send second request, I do not get any response from server.
Please make a note that, server sends message length in first two bytes and appends the rest of the response.
For second response, I get header as 0000 and response as null.
Can somebody point me to example where client is creating only one socket with server and use its input and output stream for every request. Below is code i tried.
SocketConnector.java
public class SocketConnector {
LoggerUtil log = LoggerUtil.getInstance();
final String className = "SocketConnector";
#Value("${socket.host}")
String socketHost;
#Value("${socket.port}")
int socketPort;
#Value("${socket.connection.timeout}")
int socketConnectionTimeout;
#Value("${socket.read.timeout}")
int socketReadTimeout;
#Bean
Socket socketSocket(){
Socket s = new Socket();
final String methodName = "socketSocket";
try {
s.connect(new InetSocketAddress(socketHost, socketPort), socketConnectionTimeout); // Connection timeout set to 5 seconds with socket.
s.setSoTimeout(socketReadTimeout); // Read timeout set to 2 seconds. This means socket should send response in maximum of 2 second for every request.
log.doLog(3, className, methodName, "Created Socket Connection");
} catch (IOException e) {
log.doLog(3, className, methodName, LoggerUtil.getExStackTrace(e));
}
return s;
};
}
LogonScheduler.java
#Configuration
#EnableScheduling
public class LogonScheduler {
#Autowired
#Qualifier("socketSocket")
private Socket socketSocket;
private DataInputStream socketInputStream;
private OutputStream socketOutputStream;
static LoggerUtil log = LoggerUtil.getInstance();
final static String className = "LogonScheduler";
String logonResponse = null;
byte[] reqMsg = null;
byte[] msgLen = null;
byte[] header = null;
byte[] buf = null;
byte[] response = null;
int messageLen = -1;
/*#Scheduled(fixedDelay = 17500)*/
#Scheduled(fixedDelay = 10000)
public void logonSender(){
final String methodName = "logonSender";
try {
socketInputStream = new DataInputStream(socketSocket.getInputStream());
socketOutputStream = socketSocket.getOutputStream();
/*
* Created a byte array named buf and writing to socketOutputStream
* buf = createRequest();
*/
socketOutputStream.write(buf);
header = new byte[2];
socketInputStream.read(header, 0, 2);
messageLen = Integer.parseInt(bytetoHex(header), 16);
log.doLog(4, className, methodName, "Message length received :" + messageLen);
logonResponse = bytetoHex(header);
response = new byte[messageLen];
socketInputStream.readFully(response, 0, messageLen);
logonResponse += bytetoHex(response);
log.doLog(4, className, methodName, "Response Message with header : " + logonResponse);
logonResponse = logonResponse.substring(4);
log.doLog(4, className, methodName, "Response Message without header : " + logonResponse);
} catch (Exception e) {
e.printStackTrace();
}finally{
Utils.closeResources(logonResponse, reqMsg, msgLen, header, buf, response, messageLen);
}
}
public String bytetoHex(byte[] b) {
if (isEmpty(b)) {
return null;
}
String hex = "";
for (int i = 0; i < b.length; i++) {
hex += byteToHex(b[i]);
}
return hex;
}
// Returns hex String representation of byte b
public String byteToHex(byte b) {
char[] array = {hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f]};
return new String(array);
}
}

Android - Send and receive byte

I've a tcp connection and i try to send and receive messages in byte, but I don't know how it work.
Here is my code to send:
public void write(String message) {
try {
byte[] b = message.getBytes("UTF-8");
writer.write(b.toString());
writer.newLine();
writer.flush();
} catch (IOException e) {
Log.e(MainActivity.TAG, "exception", e);
e.printStackTrace();
} catch (Exception e) {
Log.e(MainActivity.TAG, "exception", e);
e.printStackTrace();
}
}
and this for receive
String message = client.reader.readLine();
JSONObject json = new JSONObject(message);
I try again :)
How I can convert the received byte array to string with full unicode for the mysql database? I use charset Utf8m4 for my database.
This is my code
byte[] message = System.Text.Encoding.UTF8.GetBytes(client.reader.ReadLine()); // client.reader.ReadLine() is already a byte[]
string encoded = System.Text.Encoding.UTF8.GetString(message);
JToken token = JObject.Parse(encoded);
My code isn't work. I get:
{"Id":"Test","Content":"hey???"}
byte[] b = message.getBytes("UTF-8");
writer.write(b.toString());
If this is the code you're asking abut, it is senseless. It should of course be
writer.write(message);
At present you're sending something of the form [B#NNNNNNNNNNN, which is the hashcode of a byte array.
I've found a solution, thank's to #EJP.
In java (client side)
writer.write(B64.encode(message)); // message is a string
In C# (server side)
string encoded = System.Text.Encoding.UTF8.GetString(message);
JToken token = JObject.Parse(encoded);
To save the bytes in database i use blob as type.
Encoding.UTF8.GetBytes(bluuub)
To get the bytes from database
byte[] b = (byte[])reader.GetValue(0);
string bluuub = Encoding.UTF8.GetString(b);

How to reduce the time for sending data to remote server?

E.g. there are 10MB data stored in my tablet. The data has a list structure. Each entry in the list is about 3500 Bytes.
Currently, I send one entry each time with the following codes:
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(ipport+ phpHandler);
HttpResponse response = null;
try {
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "utf-8"));
response = httpclient.execute(httppost);
} catch (UnsupportedEncodingException e) {
} catch (ClientProtocolException e) {
} catch (IOException e) {
}
But to send this 10MB data, it took a long time. Each sending of an entry takes about 1 second.
Any solution to improve the efficiency?
You can build a JSON string object which contains all the entities and then compress it with gzip or any other compression scheme.
The benefit of building a JSON object is you can transmit all the objects as one request, instead of sending it separately. This would eliminate the latency of establishing a new connection everytime.
// your data list = listData
JSONArray newArray = new JSONArray();
for (int i = 0, lsize = listData.size(); i < lsize; i++) {
try {
newArray.put(i, listData.get(i));
} catch (JSONException e) {
e.printStackTrace();
}
}
This code would build a JSONArray with all the elements in the listData (it should be a list of strings)
now you can easily convert the JSONArray to a string using
newArray.toString()
Now you can send this JSON string over the network, and you can easily deserialize a JSON object in any server side language.
As for Gzip compression, you might want to look at this link
Here is a question on SO about sending GZip compressed data over HTTP in android
GZip POST request with HTTPClient in Java
I am agreeing with the answer of #Ahmed. you better use jSON string object then compress using gzip libray.
for JSON there are lots of helpful tutorials. following link is really helpful
http://www.vogella.com/articles/AndroidJSON/article.html
here you can see the simple way to write json
public void writeJSON() {
JSONObject object = new JSONObject();
try {
object.put("name", "Jack Hack");
object.put("score", new Integer(200));
object.put("current", new Double(152.32));
object.put("nickname", "Hacker");
} catch (JSONException e) {
e.printStackTrace();
}
}
and to compress and decompress using gzip Here i am adding some sample codes from the answer https://stackoverflow.com/a/6718707/931982
public static byte[] compress(String string) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
GZIPOutputStream gos = new GZIPOutputStream(os);
gos.write(string.getBytes());
gos.close();
byte[] compressed = os.toByteArray();
os.close();
return compressed;
}
public static String decompress(byte[] compressed) throws IOException {
final int BUFFER_SIZE = 32;
ByteArrayInputStream is = new ByteArrayInputStream(compressed);
GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);
StringBuilder string = new StringBuilder();
byte[] data = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = gis.read(data)) != -1) {
string.append(new String(data, 0, bytesRead));
}
gis.close();
is.close();
return string.toString();
}

how can i get the right string from a byte array which is passed over by DatagramSocket

here is the code i send the string:
byte[] buffer = txtAreaSendText.getText().getBytes();// Point A
DatagramPacket dp = new DatagramPacket(buffer,buffer.length,remoteAddr, remoteTextPort);
udpSocket.send(dp);
and here is my code for receiving the string:
byte[] buffer = new byte[1024];
DatagramPacket dp = new DatagramPacket(buffer, 1024);
try {
udpSocket.receive(dp);
String txtString = dp.getData().toString();
} catch (IOException e) {
e.printStackTrace();
}
i try to correct the code by change the code at Point A:
byte[] buffer = txtAreaSendText.getText().getBytes("utf-8");
but i can not get the right string as well.
plus, my default encoding of eclipse workspace is utf-8,and java file as well.
but i can not get the right string as well.
What are you getting?
From the looks of it you're calling toString() on a byte array and it probably returns the class type as a string (or something similar).
I believe what you should be doing is:
byte[] data = dp.getData()
String txtString = new String(data);

Can't get Java and C# to communicate through sockets

I've been trying to create a Java and C# app that would communicate together. In this case the user sends a String from the C# side, it should display on the Java console and echo back. Unfortunately, I have only been able to establish the connection, without being able to send or receive anything.
Java code snippet:
public CommunicationThreadHandler(Socket socket, CarList carList) {
this.socket = socket;
this.carList = carList;
try {
this.in = new DataInputStream(socket.getInputStream());
this.out = new DataOutputStream(socket.getOutputStream());
this.writer = new Writer(out);
} catch (IOException e) {
System.out.println("Exception when reading or receiving data!");
e.printStackTrace();
}
this.ip = socket.getRemoteSocketAddress().toString();
}
#Override
public void run() {
while (true) {
try {
Gson gson = new Gson();
String msgJson = in.readUTF();
String msg = gson.fromJson(msgJson,String.class);
System.out.println("Message from C# client: "+msg);
String reply = "Server echo: "+msg;
String replyJson = gson.toJson(reply);
out.writeUTF(replyJson);
if (msg.equals(Package.EXIT))
break;
} catch (IOException e) {
e.printStackTrace();
}
}
C# snippet:
public static void StartClient()
{
// Data buffer for incoming data.
byte[] bytes = new byte[1024];
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// This example uses port 11000 on the local computer.
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket sender = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
while (true)
{
Console.Write("Enter message to server: ");
string message = Console.ReadLine();
Console.WriteLine($"To be sent: {message}");
// Encode the data string into a byte array.
byte[] msg = Encoding.ASCII.GetBytes(message);
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Receive the response from the remote device.
int bytesRec = sender.Receive(bytes);
string msgFromServer = Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (msgFromServer.Equals("EXIT"))
break;
Console.WriteLine($"Server says: {msgFromServer}");
}
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
Your problem is that you're using DataInputStream/DataOutputStream in Java, which use a Java-specific, XDR-like datatype serialization protocol. You are not using that protocol at your C# side.
Switching to using the raw input/output stream should be sufficient (although very brittle). However, notice that as you are sending raw bytes from C#, it will be impossible to tell for the recipient when the message is complete. It would be better to send the number of bytes of the message, followed by the actual message (this is what DataInputStream/DataOutputStream does, but it comes with additional considerations that you would need to correctly implement in your C# side, for example readUTF/writeUTF use a 'modified UTF-8' format instead of normal UTF-8).
The problem right now, is that you send raw bytes from C#, the readUTF() method reads the first two bytes as length, and then tries to read a message of that length. For example if C# sends "Hello" (encoded as 0x48, 0x65, 0x6c, 0x6c, 0x6f), then the Java side will read 0x48, 0x65 ("He") as "message length is 18533" and then tries to read 18533 bytes, while the actual remaining bytes are only 3 (the "llo"). This causes the input to block waiting for the remaining 18530 bytes, which never arrive.

Categories