Referring to the Java 6 API docs for the DatagramSocket class:
UDP broadcasts sends are always enabled on a DatagramSocket. In order
to receive broadcast packets a DatagramSocket should be bound to the
wildcard address. In some implementations, broadcast packets may also
be received when a DatagramSocket is bound to a more specific address.
Could someone tell me what the 'wildcard address' is? And is the following valid for listening for UDP broadcasts:
MulticastSocket socket = new MulticastSocket(new InetSocketAddress(InetAddress.getByName("0.0.0.0"),4445);
The wildcard address is 0.0.0.0. Not to be confused with the broadcast-to-all-subnets address, which is 255.255.255.255. It is more correctly called the 'any' address, after INADDR_ANY.
In Java it is most easily used by supplying null as a bind-address, or omitting the parameter altogether, e.g. new InetSocketAddress(null, 0) or new InetSocketAddress(0) respectively. In other words it is the default when binding, and therefore implicitly 'good practice'.
Related
I've spent some time learning about UDP connections, particularly with Multicast Sockets in Java.
I was able to make a simple Multicast Socket "group chat" on my local network, but I've since been trying to expand this to work beyond my local network.
In attempts to achieve this, I port-forwarded a Class D IP address on my router in order to allow other people to access my Multicast group from outside my network.
However, when trying to connect to my "group chat" via my public IP and specified port (during the port-forwarding), I would receive the following error message...
Exception in thread "main" java.net.SocketException: Not a multicast address
at java.net.MulticastSocket.joinGroup(MulticastSocket.java:310)
...
This error makes some sense, given that my public IP isn't a class D address. But since I port-forwarded a multicast address to the specified port on my router, shouldn't this problem not occur?
Here's the relevant part of my code...
InetAddress group = InetAddress.getByName("192.___.___.___"); // my public IP
MulticastSocket socket = new MulticastSocket(1234); // the port-forwarded port
socket.joinGroup(group);
Where had I gone wrong here, and how could I get to fixing this issue?
A multicast address is between 224.0.0.0 - 239.255.255.255 with different sub-ranges within for different scenarios. More here: https://en.wikipedia.org/wiki/Multicast_address
So by attempting to join a group at 192.x.y.z, that's an invalid multicast address. That's why you get the exception thrown.
I could be mistaken, I doubt most consumer/home NAT, much less ISPs support multicast traffic. (Begs the questions - whatever happened to the MBONE - I thought that would have taken off and been the solution for everything.)
It sounds like what you need is a proxy program that intercepts multicast traffic and tunnels it to a proxy on a different network running the same code. The proxy in turn, takes the tunnelled packet and redirects back to a multicast\broadcast group.
You might have better luck with broadcast sockets instead of multicast.
This accept() method return a tuple with a new socket and an address but why do i need a new socket if i already have one, so why don't use it?
import socket
sock = socket.socket()
sock.bind(('', 9090))
sock.listen(1)
conn, addr = sock.accept()
print 'connected:', addr
while True:
data = conn.recv(1024)
if not data:
break
conn.send(data.upper())
conn.close()
ps: When i program sockets in Java, i don't really have this kind of accepting stuff and i only need one socket per client and one per server, which makes sense.
You have one listening socket active while the server is running and one new connected socket for each accepted connection which is active until the connection is closed.
Seems like you haven't implemented TCP in Java before.
The example you are providing with, uses a default AF_INET and SOCK_STREAM which by default is TCP:
socket.socket([family[, type[, proto]]])
Create a new socket using the given address family, socket type and protocol number. The address family should be AF_INET (the default), AF_INET6 or AF_UNIX. The socket type should be SOCK_STREAM (the default), SOCK_DGRAM or perhaps one of the other SOCK_ constants. The protocol number is usually zero and may be omitted in that case.
If you were implemented SOCK_DGRAM which is UDP, you wouldn't need to be using sock.accept()
When we send data (in this case) to a client/server, does this really matter to use the same port number?
My guess is no, because it doesn't matter which port you are using when sending data to. (The protocol gives it to you randomly internally - this is the idea?) The only thing has to be kept, the port has to be any availabe one on the receiver machine(above 1000, because those are reserverd by the system), and if that receiver decides to send something back, he or she will have enough information about sender: his IP address, port number ect. As far as i know, a received packed provides with all of that info.
Below is just an illustration of what i've said above.
public class Server {
public static void main(String[] args) {
GameServer server = new GameSever(9822);
server.start();
InetAddress address = null;
int port = 7877;
try {
address = InetAddress.getByName("192.168.0.2");
} catch (UnknownHostException e) {
e.printStackTrace();
}
server.send(new byte[] { 1, 2, 3 }, address, port);
}
}
When a server listens on a computer, it specifies a port it wants it's connections coming in from , so ports are important for setting up servers. This is useful as you can have multiple applications listening on different ports without the different applications accidentally talking to eachother. So you should decide on a port that isn't a standard( 80 is for HTTP for example) to exclusively use for you gameserver so the client knows which port to send the requests to.
If you want to handle multiple connections at once the best thing to do is threading.
When we send data (in this case) to a client/server, does this really
matter to use the same port number? My guess is no, because it doesn't
matter which port you are using when sending data to.
Firstly, use the terms client and server distinguishly(as generally client initiates by sending the message, to which the server responds).
Next, the port which you're using is logically of no significance, the reason being server uses request.getPort() to determine the port while seding the response; (request is a DatagramPacket sent by the client).
Though you can hardcode the port at server(if known beforehand), but, it is a bad idea. What in those applications where you've no idea about who sent the datagram packet?
Java documentation by Oracle also uses an example of client-server where client's port number is left for the constructor to pick. It mentions :
Mostly, the client uses a constructor that does not require a port number. This constructor just binds the DatagramSocket to any available local port.
It doesn't matter what port the client is bound to because the DatagramPackets contain the addressing information. The server gets the port number from the DatagramPackets and send its response to that port.
MORE INFO (taken from Java Network Programming) :
public DatagramSocket() throws SocketException
This constructor creates a socket that is bound to an anonymous port. For example:
DatagramSocket client = new DatagramSocket();
Pick this constructor for a client that initiates a conversation with a server. In this scenario, you don’t care what port the socket is bound to because the server will send its response to the port from which the datagram originated. Letting the system assign a port means that you don’t have to worry about finding an unused port. If, for some reason, you need to know the local port, you can find out with the getLocalPort() method.
NOTE : The same socket can receive the datagrams that a server sends back to it(underlying implementation).
Whereas, the below constructor creates a socket that listens for incoming datagrams on a particular port, specified by the port argument :
public DatagramSocket(int port) throws SocketException
Use this constructor to write a server that listens on a well-known port.
Short answer:
Your guess is correct.
Longer answer:
Client gets a random port number when sending data to a server and each packet has a header which contains the info about client's port, ip address ect. So server can easily retreive this information and send anything back.
Whereas the server needs to be bind to a specific port in order to clients be able to send data to that server because when you use UDP, you need to specify an IP address and a port.
I'm using multicast to implement a simple discovery service. Several instances on the application must be able to run on the same host, I therefore end up with several multicast sockets that are members of the same group on the same host.
On Linux, this works as expected. Every instance of the application on a host receives the messages sent to the multicast address.
On Windows however, only the first application to join the multicast group receives the messages sent.
Here is the code I'm using to create my multicast socket:
socket = new MulticastSocket(PORT);
InetAddress group = InetAddress.getByName(ADDRESS);
socket.joinGroup(group);
socket.setTimeToLive(TTL);
Is there some option I need to set? I've tried scouring the API but I can't find anything.
EDIT: According to this website, I need to set SO_REUSEADDR, but this can only be set before the socket binds. It seems the constructor for MulticastSocket seems to bind the socket upon creation.
you do this by creating the socket with no arguments and then call bind on that object.
socket = new MulticastSocket();
socket.setReuseAddress(true);//redundant, already set with empty constructor
SocketAddress sockAddr = new InetSocketAddress(PORT);
socket.bind(sockAddr);
InetAddress group = InetAddress.getByName(ADDRESS);
socket.joinGroup(group);
socket.setTimeToLive(TTL);
I am having an UDP Netty based server. It has a SimpleChannelUpstreamHandler pipelined where I override the messageReceived method.
I need to write back some information now and then. I could only do that by using the socket information from MessageEvent.getRemoteAddress(), and the channel from MessageEvent.getChannel(). In order to be able to reuse this information I keep in in a static map.
This turns into MessageEvent.getChannel().write("foo", MessageEvent.getRemoteAddress());
What I would have expected was to have MessageEvent.getChannel().getRemoteAddress() work, which is not the case. It always gives me null.
Am I doing something wrong ?
Is there a better way for writing back than keeping the channel and remote address in some member ?
when using a UDP (Datagram) channel as a server channel, you only bind it on a local address and no connection is made. this is why there is no remote address associated with the channel and you always get null when calling MessageEvent.getChannel().getRemoteAddress(). this behavior is expected and correct. the same single UDP "server" channel handles all incoming client requests.
when using a UDP channel as a client channel, one can create a "connection" by connecting the channel to a remote address. in this case the channel will have a configured remote address (although no actual connection is made) and calling MessageEvent.getChannel().getRemoteAddress() will return the configured remote address.
connecting a UDP channel prevents the user from using the channel to send data to remotes addresses other then the one configured on the channel. trying to do so will throw an exception. connecting a client channel is optional in UDP, a client can operate properly with a channel which is only binded on a local address as long as it saves the remote address.
I think you have two options:
saving the clients remote addresses with the client identifier and using the "server" channel to sent the data. saving the channel won't work because the same channel will used for communicating with all clients.
creating a new connected channel for each client, and saving the new channels with the client identifiers.
I believe the first option is better.
As you're probably aware UDP is a connection-less transport. A single channel can receive data from, and write data to any destination address. Therefore a UDP channel does not have an associated remote address in the way that a TCP channel does. While I think it's possible to get netty to associate a UDP channel with a specific remote address, I haven't got the details to hand and, to be honest, I think getting the address from the message event is the better option.
This leads into your second question in that, yes, you will need to keep the remote address somewhere. I've not done any UDP programming in Netty so I'm not sure if you need to map the remote address to a channel object, or whether Netty is always returning the same channel object regardless. It's worth checking this as you may only need to keep a single reference to the channel.
1) Take a look at this UDP upstream handler. To get the remote address of the sender you can use the following code SocketAddress remoteAddress = datagramPacket.sender();
2) What #johnstlr mentioned is right, it is not correct to associate a UDP channel with a single remote address. But you can use a concurrent hashmap to do lookups as shown in the above file. This game server actually uses sessions which have both TCP and UDP connections. This makes it easy to send reliable data over TCP and all the frame data over UDP.