Java Datagram Socket.recieve() freeze - java

While using datagram sockets in java for a game, a very weird issue appears. I'm trying to recieve a packet on the client but nothing happens. This is not what's weird however. I have set a timeout for the socket directly in front of the socket.receive() call and it still never times out.
What's even more odd is that the implementation seems to be working completely at random. Sometimes it works like a charm and a steady package exchange stream appears between the server and the client. In this case, I can see my friend walking around and he can see me as well. Sometimes however, the client completely freezes in the socket.recieve().
The server and client are run on separate threads and only handle network communications.
Basically, the issue is that the client socket.receive() seems to freeze and never time out. Any ideas of what might be wrong would be greatly appreciated.
The Client run() method:
public void run() {
try {
while(running) {
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
try {
System.out.println("BEFORE RECEIVE");
socket.setSoTimeout(1000);
socket.receive(packet);
System.out.println("AFTER RECEIVE");
}catch (SocketTimeoutException e) {
if(!disconnected){
System.out.println("TIMEOUT, RESENDING");
sendData(loginPacket.getData());
}
// e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
parsePacket(packet.getData(), packet.getAddress(), packet.getPort());
}
}finally {
System.out.println("SOCKET CLOSED");
socket.close();
}
}
The server run() method:
public void run() {
try {
socket.setSoTimeout(10);
while(running) {
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
try {
socket.receive(packet);
}catch (SocketTimeoutException e) {
continue;
}catch (IOException e) {
e.printStackTrace();
}
System.out.println("REcieve Packet: " + new String(packet.getData()));
parsePacket(packet.getData(), packet.getAddress(), packet.getPort());
}
}catch (SocketException e1) {
e1.printStackTrace();
} finally {
socket.close();
}
}

Related

Unable to send data to emulator from java through sockets

I run a service in android where i have a (server)socket and it listens to port 5587.I have a java (client)socket program which has to send data to the android emulator.But it cant send data to the emulator.I gave the ip address of the (server)i.e android emulator as 10.0.2.15.I also tried 10.0.0.3,10.0.0.4,10.0.0.5,10.0.0.6.But (client) java cant send data..it shows "connection timed out".My code is working fine if I give my phone ip address and run it on phone.I guess the ip address or port number is wrong.
My java program:
public class Main {
public static void main(String[] args) {
System.out.println("enter data to send to android");
mess = sc.nextLine();
try {
client = new Socket("10.0.2.15", 5587);
// emulator ip
oos = new ObjectOutputStream(client.getOutputStream());
oos.writeObject(mess);
ois = new ObjectInputStream(client.getInputStream());
message = (String) ois.readObject();
System.out.println("Message: " + message);
if(message == "Received"){
System.out.println("Message Sent Sucessfully");
}
else{
System.out.println("Message Not Sent...Try to resend");
}
//close resources
ois.close();
oos.close();
client.close();
Thread.sleep(1000);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
My android code is also running perfect and it waits for the client
so below i post the code which is run by a new Thread inside the service
public void run() {
try {
server = new ServerSocket(port);// port = 5587 and ServerSocket intialised before itself
while (true) {
System.out.println("Waiting for client request");
Socket socket = server.accept();
//read from socket to ObjectInputStream object
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
//convert ObjectInputStream object to String
String message = (String) ois.readObject();
Log.d("sri","Message Received: " + message);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

Java UDP packet only holds 5 bites

The following code is used to send over a simple string in the following formart "address,porttNum".
Here is the client side:
ByteArrayInputStream bin = new ByteArrayInputStream(packet.getData());
DataInputStream dis = new DataInputStream(bin);
try {
System.out.println("Data in packet: " + dis.readLine());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Here is the server side:
byte[] sbuf = data.getBytes();
// sbuf = output.getBytes();
packet = new DatagramPacket(sbuf,
sbuf.length, packet.getAddress(), packet.getPort());
try {
socket = new DatagramSocket();
socket.send(packet);
} catch (Exception e) {
e.printStackTrace();
}
Say the server sends "abcdefghi", the client only recieves "abcde". I have tried it with multiple test cases and the client always recieves 5 bytes. Can anyone point out where I messed up?
edit:
For debugging purposes I even added the following:
try {
System.out.println("Data in packet: " + dis.readLine());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
which outputs the right data the client still does not get it.
edit 2:
I changed the client side to the following:
String data = new String(packet.getData(), StandardCharsets.UTF_8);
System.out.println("Data in packet: " + data);
It makes no difference.
Here is some example code showing construction of a Datagram packet from the bytes of a String, sending it, and reconstruction of the String.
Notice that the buffer for receiving a packet is created much larger than the message that is eventually received. This is necessary as the the UDP socket will truncate the message to the size of the buffer if it receives a message larger than the buffer. For example, if the client sent the message "ZYXWV" to the server, and only created the buffer large enough for that message, and then reused the buffer for the incoming message, only the first 5 characters of the incoming message would be received.
public class DataGram {
public static void main(String[] args) throws SocketException {
new Thread(new Client()).start();
new Thread(new Server()).start();
}
static class Client implements Runnable {
DatagramSocket socket;
Client() throws SocketException {
socket = new DatagramSocket(1234);
}
#Override
public void run() {
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
try {
try {
socket.receive(packet);
String msg = new String(packet.getData());
System.out.println(msg);
} finally {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
static class Server implements Runnable {
#Override
public void run() {
SocketAddress address = new InetSocketAddress("localhost", 1234);
try (DatagramSocket socket = new DatagramSocket()) {
String msg = "abcdefghi";
byte[] buf = msg.getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length, address);
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
No DataInputStream or ByteArrayInputStream is used here, since you can directly convert a String to byte[] and back again.

Java networking - java.net.BindException

I'm creating a LWJGL Strategy Game, and I'm implementing multiplayer into it.
Right now the game is just generating a world with some different tile types.
I thought I should start implementing networking now, to make the server generate the world,and all clients joining download that world and load it (even though the game is barely a playable yet) to make it easier to implement more advanced stuff later on. Now to the problem!
I'm watching these tutorials on networking implementation, made by DesignsbyZephyr, but I'm getting this error:
java.net.BindException: Address already in use: Cannot bind
at java.net.DualStackPlainDatagramSocketImpl.socketBind(Native Method)
at java.net.DualStackPlainDatagramSocketImpl.bind0(Unknown Source)
at java.net.AbstractPlainDatagramSocketImpl.bind(Unknown Source)
at java.net.DatagramSocket.bind(Unknown Source)
at java.net.DatagramSocket.<init>(Unknown Source)
at java.net.DatagramSocket.<init>(Unknown Source)
at java.net.DatagramSocket.<init>(Unknown Source)
at com.tdd12.eotu.net.GameServer.<init>(GameServer.java:22)
at com.tdd12.eotu.Game.<init>(Game.java:39)
at com.tdd12.eotu.Game.main(Game.java:121)
Exception in thread "Thread-3" java.lang.NullPointerException
at com.tdd12.eotu.net.GameServer.run(GameServer.java:37)
When I start the game two times with the same port. That sounds pretty weird, doesn't it?
I don't know why, maybe because I'm not very experienced with network programming (as you've maybe already understood).
Here is the code I'm using:
(The code is placed in classes and packages, so they are correctly formatted. I just didn't write that here)
GameServer.java:
// The socket
private DatagramSocket socket;
// The main game
private Game game;
// The constructor
public GameServer(Game game) {
// Assign variables
this.game = game;
try {
this.socket = new DatagramSocket(9527);
} catch (SocketException e) {
e.printStackTrace();
}
}
// Run the thread
public void run() {
while(true) {
// The data to include in the packet (data to send)
byte[] data = new byte[1024];
// The packet to send
DatagramPacket packet = new DatagramPacket(data, data.length);
// Recieve data from the server
try {
socket.receive(packet);
} catch (IOException e) {
e.printStackTrace();
}
// Get the message
String message = new String(packet.getData());
// Print the message
System.out.println("CLIENT [" + packet.getAddress().getHostAddress() + ":" + packet.getPort() + "] > " + new String(packet.getData()));
// If the message is equal to "ping"
if(message.trim().equalsIgnoreCase("ping")) {
// Send back a message with the text "pong"
sendData("pong".getBytes(), packet.getAddress(), packet.getPort());
}
}
}
// Send data to the server
public void sendData(byte[] data, InetAddress ipAddress, int port) {
// Create a new packet with the inputed data
DatagramPacket packet = new DatagramPacket(data, data.length, ipAddress, port);
// Send the packet to the server
try {
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
GameClient.java:
// The IP address
private InetAddress ipAddress;
// The socket
private DatagramSocket socket;
// The main game
private Game game;
// The constructor
public GameClient(Game game, String ipAddress) {
// Assign variables
this.game = game;
try {
this.socket = new DatagramSocket();
this.ipAddress = InetAddress.getByName(ipAddress);
} catch (SocketException | UnknownHostException e) {
e.printStackTrace();
}
}
// Run the thread
public void run() {
while(true) {
// The data to include in the packet (data to send)
byte[] data = new byte[1024];
// The packet to send
DatagramPacket packet = new DatagramPacket(data, data.length);
// Recieve data from the server
try {
socket.receive(packet);
} catch (IOException e) {
e.printStackTrace();
}
// Print the data
System.out.println("SERVER > " + new String(packet.getData()));
}
}
// Send data to the server
public void sendData(byte[] data) {
// Create a new packet with the inputed data
DatagramPacket packet = new DatagramPacket(data, data.length, ipAddress, 9527);
// Send the packet to the server
try {
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
I'd greatly appreciate if someone could help me with this.
Thanks!
As Diptopol Dam said, calling the
DatagramSocket.close();
method before the application is closed fixed the problem. Thanks Diptopol Dam!

MulticastSocket doesn't open port

I'm trying to create a simple multicast communication between my PC (Ubuntu, client) and my phone (Android, server).
Unicast/TCP connections work without any problem, the defined port (37659) opens both on PC and phone. When trying to use a MulticastSocket, no ports get opened. nmap tells me the specified port (36963) is a TCP port and that it is closed. (While the receive-method is being executed).
Am I doing something wrong? Or is the firewall blocking the multicast sockets? (I've tried about 20 different ports and none worked..., currently using port 36963)
EDIT: Also with the firewall completely down, nmap tells me the port is closed...
The server's code (phone):
private void multicastLoop() {
String res = Build.FINGERPRINT + "\n";
final InetAddress group;
final MulticastSocket socket;
final DatagramPacket response;
try {
group = InetAddress.getByName("224.0.0.115");
socket = new MulticastSocket(mport);
socket.setLoopbackMode(true);
socket.setSoTimeout(10000);
socket.joinGroup(group);
response = new DatagramPacket(res.getBytes(), res.length(), group, mport);
} catch (IOException e) {
e.printStackTrace();
return;
}
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while(isRunning) {
try {
byte[] data = new byte[1024];
DatagramPacket dm = new DatagramPacket(data, data.length);
socket.receive(dm);
Log.d("udp", "received");
if (Arrays.equals(dm.getData(), "someone there".getBytes())) {
socket.send(response);
}
} catch (SocketTimeoutException e) {
continue;
} catch (IOException e) {
e.printStackTrace();
}
}
try {
socket.leaveGroup(group);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
}
The client's code (computer):
public String[] findServers() {
String hello = "someone there";
try {
InetAddress group = InetAddress.getByName(mhost);
MulticastSocket socket = new MulticastSocket(mport);
socket.setLoopbackMode(true);
socket.setSoTimeout(60000);
socket.joinGroup(group);
DatagramPacket p = new DatagramPacket(hello.getBytes(), hello.length(), group, mport);
byte[] buffer = new byte[1024];
socket.send(p);
DatagramPacket r = new DatagramPacket(buffer, buffer.length);
socket.receive(r);
socket.leaveGroup(group);
socket.close();
String srinfo = "";
byte[] data = r.getData();
for (byte b: data)
srinfo += (char) b;
System.out.println("Server found at " + r.getAddress().getHostName() + ": " + srinfo);
} catch (SocketTimeoutException e) {
return new String[] {"timeout"};
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Make sure mhost is set to "224.0.0.115" not some machine name.
Make sure multicast is enabled on your router.
If the host is multi-homed, you need to join the multicast group via all local interfaces, not just the default one, which is what you're doing at present.
You could send the response back to the source address it came from, which is in the received datagram packet. That would also mean that the client doesn't need a MulticastSocket, only a DatagramSocket.

Strange/unexplainable behaviour of Eclipse and multicast packets

I have a very similar behaviour as described here:
running on a Mac Book Pro, Snow Leopard
using Multicast Sockets to send and receive packets on localhost
I'm using Eclipse and observed the following behaviour when the client / server are started from within the workspace:
if the wireless interface (airport) is up and running, the client does not receive any packets
if the interface is turned off, everything works as expected
But what I don't understand is:
if I create a JAR and run the code in any console -> all good! Just Eclipse seems not to like airport ;-)
depending on what wireless network I'm connected to, the above behaviour might change, i.e. it also works if airport is enabled (for example # Uni)
Does anyone have an idea 'bout this?
Cheers
Below the straightforward code for server / client:
#Override
public void run() {
String multicastAddress = "224.0.0.2";
int multicastPort = 8000;
MulticastSocket socket = null;
try {
try {
InetAddress multicastGoup = InetAddress.getByName(multicastAddress);
socket = new MulticastSocket(multicastPort);
socket.joinGroup(multicastGoup);
} catch (IOException e) {
e.printStackTrace();
return;
}
byte[] buffer = new byte[1024];
while (true) {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
System.out.println("BEFORE RECEIVE: listening on " + multicastAddress + ":" + multicastPort);
socket.receive(packet);
System.out.println("PACKET RECEIVED");
System.err.println("Client received: " + new String(packet.getData()));
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
socket.close();
}
}
Server:
public void run() {
MulticastSocket socket = null;
try {
String multicastAddress = "224.0.0.2";
int multicastPort = 8000;
InetAddress multicastGoup = InetAddress.getByName(multicastAddress );
socket = new MulticastSocket(multicastPort);
socket.joinGroup(multicastGoup);
byte[] data = new String("Teststring").getBytes();
while (true) {
socket.send(new DatagramPacket(data, data.length, multicastGoup, multicastPort));
System.out.println("SERVER: Datagram sent");
Thread.sleep(1000);
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
socket.close();
}
}
From Class MulticastSocket:
void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
Joins the specified multicast group at the specified interface.
Try using a specific interface so your joinGroup doesn't fall into the default - which may vary according on available, open ones or due to Eclipse settings.
joinGroup
public void joinGroup(SocketAddress mcastaddr,
NetworkInterface netIf)
throws IOException
Joins the specified multicast group at the specified interface.
If there is a security manager, this method first calls its
checkMulticast method with the mcastaddr argument as its argument.
Parameters:
mcastaddr - is the multicast address to join
netIf - specifies the local interface to receive
multicast datagram packets,
-- here is the catch
or null to defer to the interface set by
setInterface(InetAddress) or
setNetworkInterface(NetworkInterface)

Categories

Resources