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.
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.
As i am using netty to make chat application.As i have cluster of netty servers.
As i am storing channel id of all clients in Redis to have reference of all channels which are connected to netty servers.
I want to store all Channel objects to Redis so that from any node or instance i can get all clients Channel objects because node on which if i want to get other clients Channel which are created on some other node, How to get those client Channel objects which reside on other node or instance?
So its better to store client Channel object to redis so from any node i can get any client Channel object. but Channel implementing class is not Serializable in netty.
So how to store Channel object in Redis?
Is it good idea to serialize Channel object by extending Channel
object and implementing Serializable interface?
If this solution is not good, then how to get any client Channel
object from any node in a netty cluster?
Thanks.
Channel in Netty contains implicitely all network aspects (socket, nio support, tcp or udp or ...), therefore you can not serialize it (a network connection cannot be serialized).
But you can serialize the remote address. Note however that the "id" is not configurable, meaning you cannot force its value for one channel. So you might use something like:
In Redis or so: (your id being the key)
your id
remote host address (and port probably)
any data for the context
In your JVM (node): (map where your id is the key)
your id
the channel object
No, you can store or persist Netty Channel in Map other than Redis.Because the channel object is unserializable.
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 am going through Sun's Java tutorial. I am in the lesson about sockets. There is the following code for a simple threaded server:
import java.net.*;
import java.io.*;
public class KKMultiServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(-1);
}
while (listening)
new KKMultiServerThread(serverSocket.accept()).start();
serverSocket.close();
}
}
The server is said to "keep listening for more incoming connections". I just don't understand how it's possible; the line serverSocket.accept() constructs a new (client) Socket object which is, according to the tutorial "bound to the same local port and has its...". Well, how is it possible that the server is communicating with the client and listening to more incoming connections on the same port? As far as I know, if a port is used for some connection it is blocked and cannot be used for more things.
So what am I getting wrong here?
Well, a socket is not one-to-one based on a port, it is unique on a tuple of (address, port). A connection - the pair of the local and remote sockets involved in the communication - is used to demux incoming data from a port to the correct socket, allowing multiple sockets on one port. See Wikipedia. In other words, the relationship of sockets to ports are N-to-1
getting multiple connections on the same port is entirely possible as each TCP connection is a (local host, local port, remote host, remote port) tuple as long as at least 1 is different the connections are distinct and won't interfere (besides bandwidth drops)
clients attempting to connect to a server generally get a port assigned from the OS that is not used currently
Listening sockets work like a receptionist in on a business's phone switch. Everyone calls the switch number, and the receptionist responds to each incoming call on the switch line by having someone else handle the call on another line. Even though the receptionist can only take one call at a time, the switch line is tied up only very briefly because it is used only to establish a connection.
[...]TCP demultiplexes incoming segments using all four values that comprise the local and foreign addresses: destination IP address, destination port number, source IP address, and source port number. TCP cannot determine which process gets an incoming segment by looking at the destination port only. Also, the only one of the [various] endpoints at [a given port number] that will receive incoming connection requests is the one in the listen state. (p255, TCP-IP Illustrated Volume 1, W. Richard Stevens)
The last sentence in the above quote is the key to understanding.
Interestingly, a socket isn't really identified by the combination of IP address and port. This is unique only in context, where the context is either a particular connection or the listening state. Only one listener socket can bind to a particular IP/port combination.
The short and sweet answer is that the port is blocked for OTHER programs and processes. Only the program that opened the port can now listen on it. BUT it can listen to many different clients on the same port.
When a client connects, it creates a unique socket. A socket is comprised of the listening IP address and port (the one you opened) AND the calling IP address and port. Because the caller's IP address and port are always unique, each socket is unique and identifiable to your listener.
Even if I connected to your program twice from the same machine, my machine would select a new and random source port for each connection -- thus ensuring that we have a unique socket each time.
Based on this link
The accept method waits until a client starts up and requests a connection on the host and port of this server (in this example, the server is running on the hypothetical machine taranis on port 4444). When a connection is requested and successfully established, the accept method returns a new Socket object which is bound to the same local port and has its remote address and remote port set to that of the client.The server can communicate with the client over this new Socket and continue to listen for client connection requests on the original ServerSocket This particular version of the program doesn't listen for more client connection requests.
Here is SO discussion which may clear confusion about how single port handles multiple client calls Port and Socket SO discussion .
To put it in simple terms, most of the webservers listen on port 8080 and multiple clients will access same port to access your website.
I'm implementing a java TCP/IP Server using ServerSocket to accept messages from clients via network sockets.
Works fine, except for clients on PDAs (a WIFI barcode scanner).
If I have a connection between server and pda - and the pda goues into suspend (standby) after some idle time - then there will be problems with the connection.
When the pda wakes up again, I can observer in a tcp monitor, that a second connection with a different port is established, but the old one remains established too:
localhost:2000 remotehost:4899 ESTABLISHED (first connection)
localhost:2000 remotehost:4890 ESTABLISHED (connection after wakeup)
And now communication doesn't work, as the client now uses the new connection, but the server still listens at the old one - so the server doesn't receive the messages. But when the server sends a message to the client he realizes the problem (receives a SocketException: Connection reset. The server then uses the new connection and all the messages which have been send in the meantime by the client will be received at a single blow!
So I first realize the network problems, when the server tries to send a message - but in the meantime there are no exceptions or anything. How can I properly react to this problem - so that the new connection is used, as soon as it is established (and the old one closed)?
From your description I guess that the server is structured like this:
server_loop
{
client_socket = server_socket.accept()
TalkToClientUntilConnectionCloses(client_socket)
}
I'd change it to process incoming connections and established connections in parallel. The simplest approach (from the implementation point of view) is to start a new thread for each client. It is not a good approach in general (it has poor scalability), but if you don't expect a lot of clients and can afford it, just change the server like this:
server_loop
{
client_socket = server_socket.accept()
StartClientThread(client_socket)
}
As a bonus, you get an ability to handle multiple clients simultaneously (and all the troubles attached too).
It sounds like the major issue is that you want the server to realize and drop the old connections as they become stale.
Have you considered setting a timeout on the connection on the server-side socket (the connection Socket, not the ServerSocket) so you can close/drop it after a certain period? Perhaps after the SO_TIMEOUT expires on the Socket, you could test it with an echo/keepalive command to verify that the connection is still good.