I am working on a server software for Minecraft: Pocket Edition. Right now I am working on the MOTD for the server, and it works Just fine. When sending a response to a ping packet (0x01) with a 0x1c. It shows up in the world list with the name just fine. But, for some reason, If I send the same data from another program, the Ping ID and ServerID will show different in the consoles. Why is this?
Ping response code:
public PingResponse(DatagramPacket Packet, long ServerID) throws IOException {
// Data from Ping
ByteBuffer ReceivedPing = ByteBuffer.wrap(Packet.getData());
// Set variables
this.ServerID = ServerID;
this.ServerName = ServerPropertiesHandler.getMOTD();
this.PingID = ReceivedPing.getLong();
// Server Name
String Identifier = "MCCPP;MINECON;" + ServerPropertiesHandler.getMOTD();
ByteBuffer PingResponseBuffer = ByteBuffer.allocate(35 + (short) Identifier.length());
// Put Packet ID
PingResponseBuffer.put(PacketIDList.ID_UNCONNECTED_PING_OPEN_CONNECTIONS);
// Ping ID
PingResponseBuffer.putLong(this.PingID);
System.out.println("Ping ID: " + this.PingID);
// Server ID
PingResponseBuffer.putLong(this.ServerID);
System.out.println("Server ID: " + this.ServerID);
// Sugar Spice and everything nice
PingResponseBuffer.put(PacketIDList.MAGIC);
// Server Name
PingResponseBuffer.putShort((short) Identifier.length());
PingResponseBuffer.put(Identifier.getBytes());
// Send
PacketHandler.Socket.send(new DatagramPacket(PingResponseBuffer.array(), PingResponseBuffer.array().length), Packet.getAddress(), Packet.getPort());
}
Client Example:
public static void main(String[] args) {
try {
// SEND
final long PacketID = new Random().nextLong();
DatagramSocket ClientSocket = new DatagramSocket();
ByteBuffer PingBuffer = ByteBuffer.allocate(25);
PingBuffer.put(PacketIDList.ID_CONNECTED_PING_OPEN_CONNECTIONS);
PingBuffer.putLong(PacketID);
PingBuffer.put(PacketIDList.MAGIC);
ClientSocket.send(new DatagramPacket(PingBuffer.array(), PingBuffer.array().length, InetAddress.getByName("localhost"), 19132));
// RECEIVE
byte[] buffer = new byte[1535];
DatagramPacket PongPacket = new DatagramPacket(buffer, buffer.length);
ClientSocket.receive(PongPacket);
byte[] PongPacketData = PongPacket.getData();
ByteBuffer PongBuffer = ByteBuffer.wrap(PongPacketData);
if(PongPacketData[0] == (byte) 0x1c) {
System.out.println("PingID From Server: " + PongBuffer.getLong());
System.out.println("ServerID From Server: " + PongBuffer.getLong());
System.out.println("MAGIC From Server: " + PongBuffer.get());
System.out.println("MOTD From Server: " + PongBuffer.get());
}
else {
System.out.println("UNKNOWN PACKET");
}
ClientSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
3 months and no reply. pingID and serverID are identifiers of time used on respective systems to determine the time since start. These provide a double functionality. Firstly, they allow a server to determine any latency in the communications. Secondly, they help provide a packet order to commands. Rebooting a server would generate a new serverID starting from 0, while rejoining a server would provide a new pingID starting at 0.
I would be quite interested to see the progress you've made, as I've begun working on my own.
Related
I have this class which opens a HTTP-Server and listens on a port. The reply is a http-header plus a json object. The class takes the input stream from the server, converts it to a string, filters the http header and parses the json object.
The thing is that the conversion from input stream to string is taking about 3 seconds. Is there a way to read the inputstream faster?
public class GamestateListener {
private static int PORT = 3001; // Port specified in your cfg
public static ServerSocket listenServer;
private static JSONObject MYJSONOBJ;
public GamestateListener() {
try {
listenServer = new ServerSocket(PORT); // open new Server Socket
System.out.println("Started Socket..."); // printing out started
// listening
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public JSONObject listenAndParseJSON() throws IOException {
System.out
.println("Listening for connection on port " + PORT + " ...."); // printing
// out
// started
// listening
try (Socket socket = listenServer.accept()) { // wait for connection
System.out.println("Start get From Socket "
+ System.currentTimeMillis());
InputStream mis = socket.getInputStream();
System.out.println("Stop get From Socket "
+ System.currentTimeMillis());
String responseString = IOUtils.toString(mis, "UTF-8");
System.out.println("Stop to String "
+ System.currentTimeMillis());
MYJSONOBJ = new JSONObject(responseString.substring(responseString
.indexOf("{")));// split the response string
return MYJSONOBJ;// return the json obj
} catch (Exception e) {
MYJSONOBJ = new JSONObject("{ERROR:True}");// create error obj
return MYJSONOBJ;// return it
}
}
}
You're not measuring what you think you are. Here:
System.out.println("Start get From Socket "
+ System.currentTimeMillis());
InputStream mis = socket.getInputStream();
System.out.println("Stop get From Socket "
+ System.currentTimeMillis());
... you seem to think that you've read all the data when getInputStream() returns. You haven't. You've just got a stream you can read from. It means there's a connection, but that's all.
If you want to measure how long it takes just to read all the data (and not actually process it) you could do something like:
System.out.println("Start get From Socket "
+ System.currentTimeMillis());
InputStream mis = socket.getInputStream();
byte[] buffer = new byte[8192];
// Read all the data (but ignore it)
while ((mis.read(buffer)) != -1) ;
System.out.println("Stop get From Socket "
+ System.currentTimeMillis());
Of course, there then won't be any data to read for the rest of the code, but you'll see how long just the data reading takes. My guess is that that'll be about 3 seconds... which could be due to slow networking, or the client taking a long time to even send all the data. (It could connect, sleep for 2.9 seconds and then send a bunch of data.)
i am working on an assignment for college, i was asked to implement a chat for the LAN of my college.
I am in the process of working with multicast for sending a same message to all registered users on the group. My sender is developed on C++ and the receivers on java. When testing on the same computer the code that i am attaching works fine, sender sends, and receiver receives, but when running client on another computer it does not receive the messages sent.
Server:
int main(){
/** MC socket **/
struct sockaddr_in groupSock;
groupSock.sin_family = AF_INET;
groupSock.sin_addr.s_addr = inet_addr("225.5.4.30");
groupSock.sin_port = htons(54321);
bzero(&(groupSock.sin_zero),8);
int mcsock;
if ((mcsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
perror("Socket MC");
exit(1);
}
int nroM = 0;
while(1)
{
fflush(stdout);
stringstream resp;
resp << "Mensaje multicast: " << nroM << "\n";
cout << resp.str();
/* Send a message to the multicast group specified by the*/
/* groupSock sockaddr structure. */
/*int datalen = 1024;*/
if(sendto(mcsock, resp.str().c_str(), strlen(resp.str().c_str()), 0, (struct sockaddr*)&groupSock, sizeof(groupSock)) < 0)
perror("Sending datagram message error");
nroM++;
sleep(2);
}
close(mcsock);
return 0;
}
Client:
class UDPCliente {
public static void main(String args[]) throws Exception{
InetAddress address = InetAddress.getByName("225.5.4.30");
// Create a buffer of bytes, which will be used to store
// the incoming bytes containing the information from the server.
// Since the message is small here, 256 bytes should be enough.
byte[] buf = new byte[256];
// Create a new Multicast socket (that will allow other sockets/programs
// to join it as well.
try (MulticastSocket clientSocket = new MulticastSocket(54321)){
//Joint the Multicast group.
clientSocket.joinGroup(address);
while (true) {
// Receive the information and print it.
DatagramPacket msgPacket = new DatagramPacket(buf, buf.length);
clientSocket.receive(msgPacket);
String msg = new String(buf, 0, buf.length);
System.out.print(msg);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
Just for extra information, this code with the appropiate imports and includes compile and run.
Thank you!!
Well, apparently i changed to another computer and the code worked. So the firewall had something to do. Im answering so if anybody needs the same problem, the code i attached works perfectly if including and importing the proper libraries!!
My server creates a multicast socket which listens for UDP packets. It is receiving packets sent to the broadcast address of the network but I can't get the ip address of the sender:
multisocket.getInetAddress().getHostAddress();
returns
"::"
(I guess its because of null getInetAddress).
How can I get the IP address of the sender?
TIPS: I guess it has to do with the socket not being bound and basically the whole broadcasting because those packets arent sent exclusively to me but to the whole network, but shouldnt they hold the IP address of the sender? Enlighten me please.
Here is the code:
public void run() {
try {
Thread.sleep(5000);
Log.i("SERVERUDP", "Connecting...");
MulticastSocket multisocket = new MulticastSocket(SERVERPORT);
multisocket.setBroadcast(true);
Log.i("SERVERUDP","Server's IP is: " + multisocket.getLocalAddress().getHostAddress());
getLocalIpAddress();
while(true){
byte[] b = new byte[65535];
ByteArrayInputStream b_in = new ByteArrayInputStream(b);
DatagramPacket dgram = new DatagramPacket(b, b.length);
multisocket.receive(dgram); // blocks
ObjectInputStream o_in = new ObjectInputStream(b_in);
Object o = o_in.readObject();
dgram.setLength(b.length);
b_in.reset();
if(o.getClass().getSimpleName().equalsIgnoreCase("Request")){
Request request = (Request)o;
String inetaddress = multisocket.getInetAddress().getHostAddress();
Log.i("SERVERUDP-if", "Sending request to IP: " + inetaddress);
new Thread(new ClientTCP(inetaddress, createRequestFromBroadcast(request))).start();
}else if(o.getClass().getSimpleName().equalsIgnoreCase("String")){
Log.e("SERVERUDP-elseif-string", "WTF received a string: " + (String)o);
}else{
Log.e("SERVERUDP-else", "Unrecognized object of type: " + o.getClass().getSimpleName());
}
o_in.close();
//iteration done only once for testing!
break;
}
multisocket.close();
} catch (Exception e) {
Log.e("SERVERUDP", "Error", e);
}
}
Each packet that you receive might have a different source address. So I'm not sure why you're trying to look at multisocket to figure out the source address.
I have to admit I haven't tried this, but does dgram.getSocketAddress () give you what you want after the multisocket.receive call returns?
Morning.
I'm pretty new in Java and socket connections but I'm trying to send out a UDP packet/broadcast on 255.255.255.255 on port 8001 to a device. I can get the data to send just fine, however when it comes time to receive the data the connection times out. I have a packet sniffer and I can see the packet send and then the device respond.
I'm pretty sure it is a rookie mistake that I'm missing in my code but I've been stuck on it for awhile and any help would be appreciated.
m_Socket = new DatagramSocket(m_SERVERPORT);
InetAddress address = InetAddress.getByName(m_SERVERIP);
m_DataPack = new DatagramPacket(m_SERVERCMD.getBytes(), m_SERVERCMD.getBytes().length,
address, m_SERVERPORT);
m_Socket.setBroadcast(true);
m_Socket.connect(address, m_SERVERPORT);
m_Socket.send(m_DataPack);
m_DataPack = new DatagramPacket(data, data.length,
address, m_SERVERPORT);
m_Socket.receive(m_DataPack); // This is where it times out
data = m_DataPack.getData();
String received = data.toString();
System.out.println("Received: " + received);
m_Socket.close();
Thanks and Gig'Em.
EDIT:
I'm not sure if this helps but when I watch the m_Socket object I can see the following right before it sends:
bound = true;
close = false;
connectedAddress = Inet4Address (id = 32) (-1,-1,-1,-1);
connectedPort = 8001;
connectState = 1;
created = true;
impl = PlainDatagramSocketImpl;
oldImpl = false;
and the m_DataPack object is the following:
address = Inet4Address (id = 32) (-1,-1,-1,-1);
bufLength = 6 (size of packet I'm sending is 6 char long);
offset = 0;
port = 8001;
This doesn't make sense. You are broadcasting, which is 1-to-many, and you are also connecting, which is 1-to-1. Which is it?
Lose the connect. And lose the 255.255.255.255. This has been heavily deprecated for about 20 years. Use a subnet-local broadcast address, e.g. 192.168.1.255.
You can also take a look at MulticastSocket described at Broadcasting to Multiple Recipients. Hope this helps.
If you want to receive a datagram you need to bind() to the local endpoint (address + port).
You are sending and receiving the packet on same device. You could separate send and receive ports (e.g send on 8001, receive on 8002). And run send and receive codes as separate threads. If both device must find each other (or one device find itself).
import java.io.IOException;
import java.net.*;
Receiving:
private DatagramSocket getReceiveSocket() throws UnknownHostException, SocketException {
if (receiveSocket == null) {
receiveSocket = new DatagramSocket(8002, InetAddress.getByName("0.0.0.0")); // 0.0.0.0 for listen to all ips
receiveSocket.setBroadcast(true);
}
return receiveSocket;
}
public void receive() throws IOException {
// Discovery request command
byte[] buffer = "__DISCOVERY_REQUEST__".getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
getReceiveSocket().receive(packet);
System.out.println("Discovery package received! -> " + packet.getAddress() + ":" + packet.getPort());
// Get received data
String data = new String(packet.getData()).trim();
if (data.equals("__DISCOVERY_REQUEST__")) { // validate command
// Send response
byte[] response = new byte["__DISCOVERY_RESPONSE".length()];
DatagramPacket responsePacket = new DatagramPacket(response, response.length, packet.getAddress(), packet.getPort());
getReceiveSocket().send(responsePacket);
System.out.println("Response sent to: " + packet.getAddress() + ":" + packet.getPort());
} else {
System.err.println("Error, not valid package!" + packet.getAddress() + ":" + packet.getPort());
}
}
Sending:
private DatagramSocket getSendSocket() throws UnknownHostException, SocketException {
if (sendSocket == null) {
sendSocket = new DatagramSocket(8001, InetAddress.getLocalHost());
sendSocket.setBroadcast(true);
}
return sendSocket;
}
public void send() throws IOException {
// Discovery request command
byte[] data = "__DISCOVERY_REQUEST__".getBytes();
DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("255.255.255.255"), 8002);
getSendSocket().send(packet);
System.out.println("Discovery package sent!" + packet.getAddress() + ":" + packet.getPort());
// Discovery response command
byte[] response = new byte["__DISCOVERY_RESPONSE__".length()];
DatagramPacket responsePacket = new DatagramPacket(response, response.length);
getSendSocket().receive(responsePacket);
System.out.println("Discovery response received!" + responsePacket.getAddress() + ":" + responsePacket.getPort());
String responseData = new String(responsePacket.getData()).trim();
if (responseData.equals("__DISCOVERY_RESPONSE__")) { // Check valid command
System.out.println("Found buddy!" + responsePacket.getAddress() + ":" + responsePacket.getPort());
}
}
Of course should put this code in a loop in a thread.
Based on this example: https://demey.io/network-discovery-using-udp-broadcast/
UPDATE
The link above is dead. But same method described here also: https://www.baeldung.com/java-broadcast-multicast
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.