I'm about to program a server but am wondering if what I have in mind is possible. My program will be outputting to multiple clients on multiple ports - each port can be accessed by multiple clients.
Normally I would use a threaded socket server, but in this case I need it working for multiple ports. The usage I have in mind is in a vague pseudocode below:
- Star开发者_运维百科t server
- Listen for incoming connections on several ports
- Identify the port being connected to
- If port 1, start a thread listening to client and outputting message type
x
- If port 2, start a thread listening to client and outputting message type
y
- If port 1, start a thread listening to client and outputting message type
Hopefully that makes some sense and you can see what I'm trying to do. Simply put: listen to selected ports, create a threaded socket connection based on which port is being connected to.
Is this doable at all, or am I going to end up multi-threading threaded socket servers?
Edit: Changed wording to better reflect the question.
It's not possible to for a single instance of ServerSocket
to listen to multiple ports. You can of course have multiple ServerSocket
s. However, as you already know, ServerSocket.accept
blocks.
What you can use instead is a ServerSocketChannel
. They're used in a similar way, but do not block.
If there are no pending connections when ServerSocketChannel.accept
is called then it simply returns null.
You can use with a Selector
which takes a set of channels and blocks until at least one has a pending connection.
I don't remember the specifics on how to use them, but this seems to be a decent code example.
edit: Here is my own example (pseudo-ish)
Selector selector = Selector.open();
int[] ports = {4000,4001,6000};
for (int port : ports) {
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
server.socket().bind(new InetSocketAddress(port));
// we are only interested when accept evens occur on this socket
server.register(selector, SelectionKey.OP_ACCEPT);
}
while (selector.isOpen()) {
selector.select();
Set readyKeys = selector.selectedKeys();
Iterator iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
if (key.isAcceptable()) {
SocketChannel client = server.accept();
Socket socket = client.socket();
// create new thread to deal with connection (closing both socket and client when done)
}
}
}
// tidy up selector and channels
Hello, so let me get this straight. What you want to do is to create a server that can listen on multiple ports and when you get a new connection, you want to be able to tell which port that connection used, is this correct? Well if that's the case, you can do this very easily with use of the java.nio
package.
We're going to use a Selector for readiness selection and a ServerSocketChannel to listen for incoming connectings.
First we need to declare our Selector
.
Selector selector = Selector.open();
Now lets create a list of ports to listen on and start listening on them.
int ports[] = new int[] { 1234, 4321 };
// loop through each port in our list and bind it to a ServerSocketChannel
for (int port : ports) {
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.socket().bind(new InetSocketAddress(port));
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}
Now for the SelectionKey
handling process.
while (true) {
selector.select();
Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
SelectionKey selectedKey = selectedKeys.next();
if (selectedKey.isAcceptable()) {
SocketChannel socketChannel = ((ServerSocketChannel) selectedKey.channel()).accept();
socketChannel.configureBlocking(false);
switch (socketChannel.socket().getPort()) {
case 1234:
// handle connection for the first port (1234)
break;
case 4321:
// handle connection for the secon port (4321)
break;
}
} else if (selectedKey.isReadable()) {
// yada yada yada
}
}
}
Perhaps a switch statement is not necessary for such a simple task, but it's for ease of reading and understanding.
Remember, this server is set up in a non-blocking asynchronous way so that all the I/O calls you perform will not block the current thread. So DO NOT initiate any new threads in the SelectionKey
handling process.
Also, I know that this doesn't completely answer your question (it might, it might not) but it will in fact give you an understanding on how to use the java.nio
package to create a non-blocking asynchronous server that can listen on multiple ports.
You can't listen to all ports, but you can listen to a set of them. Create one ServerSocket
( http://download.oracle.com/javase/6/docs/api/java/net/ServerSocket.html#ServerSocket%28int%29 ) for each port you want to listen to, and accept connections on each.
This should be possible with NIO, however I don't see a good reason to avoid having one thread per listener unless you have more than 1K port.
Do you really need multiple listening ports? In most cases it should be possible for one port support all kinds of clients and have the client tell the server (or the server determine what type of connection is needed)
I don't think you can listen to all ports, no. That would be quite expensive for the OS to implement, so that's simply not how port listening works.
What if multiple applications were simultaneously listening to "all" ports, to which application should the network subsystem deliver incoming packets?
精彩评论