Java Multicast Sending Data, Not Receiving - java

I am writing a class in Java which is used to greatly simplify the process of multicasting. However, I am having two big problems with it:
The class sends data (I can verify this with my net monitor, Wireshark) but the data is not received by any others in the same group.
On some machines, the sending packet TTL is exceeded in transit (again, according to Wireshark).
Could anyone please help me? I've been trying and searching for answers for hours, and it appears that my code follows all of the basic procedures for connecting to, joining, sending, and receiving data from a multicast host.
Here is a snippet of the relevant portions of the class:
Multicaster class:
public class Multicaster {
public int port = 5540;
protected String IPAddress;
private MulticastSocket msConn;
private InetAddress netAddr;
public Multicaster(String IPAddress) {
this.IPAddress = IPAddress;
}
public String recieveData() {
byte[] buf = new byte[1000];
DatagramPacket pack = new DatagramPacket(buf, buf.length);
try {
this.msConn.receive(pack);
new Message(pack);
String out = new String(pack.getData());
return out.substring(0, pack.getLength());
} catch (IOException e) {
return new String("");
}
}
public void joinGroup() {
try {
this.msConn.joinGroup(this.netAddr);
} catch (IOException e) {
//This error shouldn't occur since it would caught by the connect() method during initial connection to the host
}
}
public void connect() throws MulticasterInitException {
//Try to create a multicast connection on the given IP address and port
try {
try {
//Create a multicast connection on a given port, throws UnknownHostException
this.msConn = new MulticastSocket(this.port);
//If all goes well, then create a connection to a given IP address using the above port number, throws IOException and SecurityException
this.netAddr = InetAddress.getByName(this.IPAddress);
}
}
/**
* Here all of the possible exceptions that are thrown above
* are caught and handled here. This works just fine.
*/
}
public void sendData(String data) throws MulticasterSendException {
DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(), this.netAddr, this.port);
try {
this.msConn.send(packet);
} catch (IOException e) {
throw new MulticasterSendException("Java could not communicate with the server. Please check your network connections.", e);
}
}
}
Sample usage to send data:
Multicaster multicast = new Multicaster("239.0.0.0");
try {
multicast.connect();
} catch (MulticasterInitException e) {
//Handle exception...
}
multicast.joinGroup();
try {
multicast.sendData("Hi");
} catch (MulticasterSendException e) {
//Handle exception...
}
Sample usage to receive data:
Multicaster multicast = new Multicaster("239.0.0.0");
try {
multicast.connect();
} catch (MulticasterInitException e) {
//Handle exception...
}
multicast.joinGroup();
System.out.print(multicast.recieveData());

I've run into similar problems before and had to ensure that the NetworkInterface was specified on the receiving side.
SocketAddress socketAddress = new InetSocketAddress(groupIp, groupPort);
NetworkInterface networkInterface = NetworkInterface.getByName(interfaceName);
socket.joinGroup(socketAddress, networkInterface);
Where interfaceName is one of the interface names shown when running ifconfig on Linux or Mac.

Related

Unable to receive datagram over the internet

I have a UDP client sending packets to my UDP server.
The packets are sent and received successfully when I use the server's IP address or the when I use the router's public IP address
// Works
Constants.SERVER_IP_ADDRESS
// Works
Constants.PUBLIC_IP_ADDRESS;
However, I'm not able to receive any packet when sending over the internet even though I've set up forwarding.
Any idea why? Thanks.
UdpClient
public class UdpClient {
private String mServerAddress = Constants.PUBLIC_IP_ADDRESS;
private int mServerPort = Constants.PORT;
private static final int MAX_TRIES = 5;
public void sendDatagramPacket(){
// Cannot network on Main UI thread
new AsyncTask(){
#Override
protected Object doInBackground(Object[] objects) {
System.out.println("sendDatagramPacket");
// Create a socket
DatagramSocket socket = null;
try{socket = new DatagramSocket();}
catch (SocketException e){e.printStackTrace();}
// Create a datagram
byte[] bytesToSend = new byte[3];
bytesToSend[0] = (byte) 255;
bytesToSend[1] = (byte) 255;
bytesToSend[2] = (byte) 255;
InetAddress serverInetAddress = null;
try{serverInetAddress = InetAddress.getByName(mServerAddress);}
catch (UnknownHostException e) {e.printStackTrace();}
DatagramPacket datagramPacket = new DatagramPacket(
bytesToSend, bytesToSend.length, serverInetAddress, mServerPort);
// Send packet; packets may be lost, so we have to keep trying
int tries = 0;
while(tries < MAX_TRIES) {
try{socket.send(datagramPacket);}
catch (NullPointerException e){e.printStackTrace();}
catch (IOException e){e.printStackTrace();}
tries++;
}
try{socket.close();}
catch (NullPointerException e){e.printStackTrace();}
return null;
}
}.execute();
}
}
UdpServer
public class UdpServer {
private int mHostPort = Constants.MAC_PORT;
// Defines max receive-buffer size; maximum possible for UDP is ~64,000
private static final int MAX_BUFFER_SIZE = 256;
public void listenForPacket(){
System.out.println("listenForPacket");
new Thread(){
#Override
public void run(){
// Get the socket to the receiving port
DatagramSocket socket = null;
try { socket = new DatagramSocket(mHostPort);}
catch (SocketException e){e.printStackTrace();}
// Create receive-buffer and receive-packet
byte[] receiveBuffer = new byte[MAX_BUFFER_SIZE];
DatagramPacket datagramPacket = new DatagramPacket(receiveBuffer,MAX_BUFFER_SIZE);
// Pause thread here listening for packet
try{
socket.receive(datagramPacket);
System.out.println("Datagram received successfully");
}
catch (IOException e){e.printStackTrace();}
try{socket.close();}
catch (NullPointerException e){e.printStackTrace();}
}
}.start();
}
}
This answer doesn't directly address your problem, but it could do indirectly. (Your bad exception handling could be hiding other problems ...)
You have systemic problems in the way that you deal with exceptions. For example:
DatagramSocket socket = null;
try { socket = new DatagramSocket(mHostPort);}
catch (SocketException e){e.printStackTrace();}
What happens if an exception is thrown by the constructor?
Answer: you print a stack trace, and then keep going as if nothing bad happened.
Except that something bad did happen. Indeed, if the constructor failed, and you don't have a DatagramSocket, then the remaining code cannot possibly work. But you "recovered".
This pattern is repeated in a number of places. Indeed you end up with code to catch NPEs that are directly caused by incorrect "recovery" code.
This the right way to do it:
public void run() {
try (DatagramSocket socket = new DatagramSocket(mHostPort)) {
// Get the socket to the receiving port
DatagramSocket socket = new DatagramSocket(mHostPort);
// Create receive-buffer and receive-packet
byte[] receiveBuffer = new byte[MAX_BUFFER_SIZE];
DatagramPacket datagramPacket =
new DatagramPacket(receiveBuffer,MAX_BUFFER_SIZE);
// Pause thread here listening for packet
socket.receive(datagramPacket);
System.out.println("Datagram received successfully");
}
catch (IOException | RuntimeException e) {
e.printStackTrace();
}
}
Things to note:
As well as being more correct (I claim), this code is actually simpler than your version. There are fewer error cases, and (I claim) the source of those pesky NPE's has been eliminated.
The exception handling does not attempt to recover. If an exception occurs, the thread will end ... immediately
Note the use of try-with-resources to ensure that the socket is always closed.
Catching RuntimeException is probably unnecessary ... see above about NPEs.
An alternative to handling the exception in the run() method would be to use a default exception handler.

Java Communication netty server - Socket client

For a chat server project I use netty as server, with the following code in my handler :
public class PacketHandler extends ChannelInboundHandlerAdapter{
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf in = (ByteBuf) msg;
try {
AbstractClientPacket packet = ClientPacketHandler.handle(in);
if(packet != null && packet.read()){
packet.run();
ctx.write(msg+"\r\n");
}
} finally {
ReferenceCountUtil.release(msg);
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
So, my packet is correctly handled and it works fine, but then, i do ctx.write(msg+"\r\n"); to send back the message to my client, acting like an echo server.
Here is the Client's code :
public class ChatClient {
static Socket socket;
static DataOutputStream out;
static BufferedReader in;
public static void main(String[] args){
try {
initSocket();
String test = "Salut 1";
TestPacket packet = new TestPacket(0x18,test.getBytes());
sendPacket(packet);
while(true){
try {
String message = in.readLine();
System.out.println(message);
} catch (IOException e) {
e.printStackTrace();
}
}
//TEST
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private static void initSocket(){
try {
socket = new Socket("localhost",58008);
out = new DataOutputStream(socket.getOutputStream());
in = new BufferedReader(new InputStreamReader((socket.getInputStream())));
} catch (IOException e) {
e.printStackTrace();
}
}
private static void sendPacket(TestPacket p) throws IOException{
out.write(p.getRawData());
out.flush();
}
}
The packet is correctly sent, but i get nothing as reply, and when i stop my server, the client is spamming null because of my while(true), but i don't get my message back, nothing is displayed and i really don't know why.
I can't use netty for the client because this one is just for test purpose, the final client will be written in C# (Unity Engine), so i can't use netty in this one, I have to do it with native socket handling.
EDIT:
According to wireshark, The packet from client is sent but the server answer is not, i don't see the packet From server containing "Salut 1".
You did:
ctx.write(msg+"\r\n");
msg is not a String but a ByteBuf. If you want to append \r\n to the received message, you should do the following:
in.writeByte('\r');
in.writeByte('\n');
ctx.write(in);
Also, because you reused the received message (in) as a response, you should not release it:
// Do NOT call this.
ReferenceCountUtil.release(in);
If you really intended to call ctx.write(msg + "\r\n"), please make sure that your pipeline has StringEncoder.

Java - SocketException: Not a multicast address

I have multiple servers on my network that all send out a broadcast message. With the following client I am trying to capture all the broadcast messages from all servers. The sending part works fine(not included in this post), but my receiving part doesn't work... I keep getting "SocketException: Not a multicast address", what am I doing wrong?
public static String[] capture(int port) { // port is always 63332
ArrayList<String> clients = new ArrayList<>();
InetAddress address = Utilities.getBroadcastAddress(); // I get "/192.168.2.255" here
MulticastSocket socket = null;
try {
socket = new MulticastSocket(port);
socket.setSoTimeout(2000);
socket.joinGroup(address); // this part throws the exception
DatagramPacket packet;
byte[] packetContent;
while (true) {
packetContent = new byte[1024];
packet = new DatagramPacket(packetContent, packetContent.length);
try {
socket.receive(packet);
String client = packet.getAddress() + ":" + packet.getPort();
clients.add(client);
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if(socket != null) {
try {
socket.leaveGroup(address);
} catch(IOException e) {
e.printStackTrace();
}
socket.close();
}
return clients.toArray(new String[clients.size()]);
}
You are confusing broadcasting with multicasting. A multicast address is not a broadcast address. Make up your mind which it is that you're doing. If you're receiving multicasts, you need to join the correct multicast address, whatever it is. If you're receiving broadcasts, don't join anything.

Socket issue c# client to java server

This is my problem, all the messages sent from the c# client aren't received by the server until that I Shutdown the socket on client side and finally the server receive all data in once time.
c# client side
public static class AsynchronousClient
{
// The port number for the remote device.
private const int port = 8888;
// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone =
new ManualResetEvent(false);
private static ManualResetEvent sendDone =
new ManualResetEvent(false);
private static ManualResetEvent receiveDone =
new ManualResetEvent(false);
public static Socket client;
// The response from the remote device.
private static String response = String.Empty;
public static void StartClient()
{
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// The name of the
// remote device is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.GetHostEntry("127.0.0.1");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 8888);
// Create a TCP/IP socket.
client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
// Send test data to the remote device.
Send(client, "test connection");
sentDown.WaitOne();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
Console.WriteLine("Socket connected to {0}",
client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static void Send(Socket client, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
client.BeginSend(byteData, 0, byteData.Length, SocketFlags.None,
new AsyncCallback(SendCallback), null);
}
public static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
// Signal that all bytes have been sent.
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
Java server side
public class Connection_to_port extends Thread {
final static int port = 8888;
private Socket socket;
String message = "";
public static void main(String[] args) {
try {
ServerSocket socketServeur = new ServerSocket(port);
while (true) {
Socket socketClient = socketServeur.accept();
Connection_to_port t = new Connection_to_port(socketClient);
t.start();
System.out.println("Connected to client : " + socketClient.getInetAddress());
}
} catch (Exception e) {
e.printStackTrace();
}
}
public Connection_to_port(Socket socket) {
this.socket = socket;
}
public void run() {
handleMessage();
}
public void handleMessage() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
message = in.readLine();
System.out.println(message);
}
catch (Exception e) {
e.printStackTrace();
}
}
In my client i have to send some data to the server like that
AsynchronousClient.Send(AsynchronousClient.client, "{myjsondata}");
My client is just for sending, not receive.
The problem is, my java server receive nothing ! But the client said it's sent, and i see on Wireshark that's it's send.
When i do
AsynchronousClient.client.Shutdown(SocketShutdown.Both);
Finally i see all my message on the server at the same time. Like if i sent only one message.
The Java side is trying to read a line (you are using readLine).
This method will not return until either there is an end-of-line character, or the stream is closed.
When you shutdown the client, in effect, the stream closes.
Your test message does not include an end-of-line character, so the only way for readLine to return is at the end of stream.
When you write to a socket, the message does not sent, it's saved in buffer until:
Buffer is full
You request to clean/flush the buffer
You shutdown.
Try the following methods:
http://msdn.microsoft.com/en-us/library/system.net.sockets.socketoptionname.aspx
http://angrez.blogspot.co.il/2007/02/flush-socket-in-net-or-c.html

Java UDP packet read failing

I am trying to send packets from one host to another peer host using java UDP protocol.
The one host sends data, while the other reads it. The corresponding read however keeps blocking, thus receiving no data. I can see the sender packets going to the right destination using wireshark, but the receiver just wont pick it up. The read operation keeps blocking indefinitely.
Please help.
Code for cient:
//CLIENT CLASS
//Sections ommited....
DatagramSocket so = new DatagramSocket(port);
protected void send(byte[] buffer,int packetsize){
DatagramPacket p;
try {
myClient.notifyInform("Sending data to "+inetaddress+" on"+port+"\n");
p=new DatagramPacket(buffer,buffer.length,InetAddress.getByName(inetaddress),port);
writeLock.lock();
try{
so.send(p);
}finally{
writeLock.unlock();
}
} catch (UnknownHostException e) {
myClient.perror("Could not connect to peer:"+e.getMessage()+"\n");
e.printStackTrace();
} catch (IOException e) {
myClient.perror("IOException while sending to peer.\n");
e.printStackTrace();
}
}
protected DatagramPacket read(){
byte[] buf=new byte[bufsize];
DatagramPacket p=new DatagramPacket(buf,buf.length);//TODO check these values, what should buffer be? just made it psize*10 for now
readLock.lock();
try{
myClient.notifyInform("receiving data\n");
so.receive(p);
this.myclient.notifyInform(String.valueOf(p.getData().length)+"\n");
} catch (IOException e) {
myClient.perror("IOException while reading from peer.\n");
e.printStackTrace();
}finally{
readLock.unlock();
}
return p;
}
protected void beginRead() {
while(active) {
System.out.println("########################");
byte[] data=this.read().getData();
myClient.notifyInform("Receiving data\n");
}
}
protected void beginSend(){
forkWork(new Runnable(){
#Override
public void run() {
byte[] sendBuffer=new byte[bufsize];
int cnt;
while(callActive){
try{
sourceLock.lock();
cnt=dataSource.read(sendBuffer, 0, bufsize);
}finally{
sourceLock.unlock();
}
if (cnt >0) {
send(sendBuffer, packetsize);
}
}
}
});
}
UPDATE:I made a mistake that I finally tracked down. After binding the port, and fixing that error, it now works.
You need to specify the port that the datagram socket is listening on like this:
this.so = new DatagramSocket(SOME_NUMBER_HERE);
and make sure you send it to the same port number in the send() method
Is your receiving DatagramSocket listening at the IP:port the sender is sending to?

Categories