I need to question about 11M nameservers and to find out which of them alive. In Java I use async sockets to send udp-requests and everything ok until I try to use multiple threads. The speed rises proportionally, but positive responses decrease dramatically, although I use a high-perfomance 16-core cluster.
I create a separate channel per thread and see no obvious reason why this happening. Can anyone explain what I'm doing wrong and is it okay to use different async sockets in threads?
Here's some code. So I have a lot of threads with id and it's list of hosts, each of them do the following:
#Override
public void run() {
DatagramChannel channel = null;
try {
channel = DatagramChannel.open();
InetSocketAddress isa = new InetSocketAddress(Settings.LOCAL_PORT+id);
channel.socket().bind(isa);
channel.configureBlocking(false);
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
ByteBuffer outBuffer = ByteBuffer.wrap(Settings.QUERY);
ByteBuffer inBuffer = ByteBuffer.allocate(200);
while (true) {
selector.select();
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (!key.isValid()) {
continue;
}
if (key.isReadable()) {
inBuffer.clear();
channel.receive(inBuffer);
inBuffer.flip();
inCounter++;
//some analize of response
continue;
}
if (key.isWritable()) {
if (outCounter < hosts.size()) {
channel.send(outBuffer, new InetSocketAddress(hosts.get(outCounter), Settings.DNS_PORT));
outBuffer.flip();
outCounter++;
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (channel != null)
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
As UDP is an unreliable protocol, you have to be careful not to overload your system or your network buffers or packets will be lost. How to do this is likely to be sensitive to a number of factors, so it doesn't surprise me that doing this a little differently could improve your response rate.
Are you using UDP Datagrams or TCP Sockets? Why are trying to poll 11 million names servers?
Related
I'm using a function to read bytes from non-blocking SocketChannel (socket from accept()) and from blocking SocketChannel (client side). I'm implementing a server using selector to handle multiple clients, and I'm using loopback address to use my laptop only. I wrote this
while((r = socketChannel.read(ackBuf)) != -1) {
System.out.println(name3d+" r: "+r);
}
and I expected that when the end of the content in the channel was reached, read() would returned -1 but is not what succedes.
read(), in non-blocking configuration, return 0 also if nothing is ready to read at the moment but it will be soon (if I understand well) so if I change the code to
while((r = socketChannel.read(ackBuf)) > 0) {
System.out.println(name3d+" r: "+r);
}
I will not read nothing also if something will be ready a moment later.
How can I distinguish if I got 0 because is not ready or because it is ended?
In the following snippet I can test for a second time the read after a sleep but I'm sure is not the reliable way to do what I want.
int times = 0;
while((r = socketChannel.read(ackBuf)) != -1 && times<2) {
if (r == 0)
try {
Thread.sleep(500);
times++;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name3d+" r: "+r);
}
" if I got 0 because is not ready or because it is ended?" Do you mean the message or the totality of the communication?
For the message, you should use a communication protocol (like json or http) for the communication, I think you should get a SocketException... You would if you using blocking and the person on the other end closed the connection... (I've written to a lot of people on SO about how SocketException is your friend)
--- edit ---
Looking over the documention for Channel, it looks like you should get an IOException of some kind (SocketException is a subclass of IOException) if/when the channcel is closed
The Non-blocking SocketChannel is used a bit different.
You first wait for the selection key to tell you that there is data, and
then you read that data from the channel.
See this code draft:
Selector selector = Selector.open();
SocketChannel sc = SocketChannel.open();
sc.configureBlocking(false);
sc.connect(addr);
sc.register(selector, SelectionKey.OP_READ);
while (true) {
// select() can block!
if (selector.select() == 0) {
continue;
}
Iterator iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
if (key.isReadable()) {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer bb = ByteBuffer.allocate(1024);
sc.read(bb);
System.out.println("Message received!");
}
}
Hi there,
I'm reading the book [Java Network Programming](http://sufuq.com/books/java/Java%20Network%20Programming,%204th%20Edition.pdf) to study a way of creating my own web server and i reached a page where it talks about multithreaded server and how to writing to it using the [echo protocol](https://www.rfc-editor.org/rfc/rfc862) as an example (page 293).
Here is the code i'm talking about:
ServerSocketChannel sChannel = null;
Selector selector = null;
try {
sChannel = ServerSocketChannel.open();
ServerSocket echoServer = sChannel.socket();
InetSocketAddress addr = new InetSocketAddress(PORT);
selector = Selector.open();
echoServer.bind(addr);
sChannel.configureBlocking(false);
sChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server running.");
} catch (IOException e) {//If something goes wrong, the server must be stopped
e.printStackTrace();
}
while(true) {
try {
selector.select();
} catch (IOException e) {
e.printStackTrace();
}
Set<SelectionKey> readyKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = readyKeys.iterator();
And my question is about
selector.select()
because that method it's supposed to block the thread when there is no channel registered to this selector but i don't really know how it can create a new channel when a client tries to connect or how this channel is created and when.
I tried reading the documentation and Java NIO by Ron Hitchens book but i didn't succeed, Can anyone explain me this please?
I just found that the problem might due to multi-threading problem. After the read() method I sent the request to several worker threads to process the data. When the thread pool size is 1, the problem doesn't occur. However, when the thread pool size is bigger than 1, this problem occurs.
I initialized my threadpool before the while(true) loop, and execute my worker thread after the read() method.
I'm using Java NIO in a middleware that connects a memtier client and a memcached server. The system works fine with only one clients connected, however, when there are more clients connected, when one client finishes and closes its channel, the other client won't be able to read or write to its channel any more.
My implementation looks like the following:
public void run() {
try{
// Connect to client
selector = Selector.open();
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
InetSocketAddress address = new InetSocketAddress(8000);
server.socket().bind(address);
server.register(selector,SelectionKey.OP_ACCEPT);
// Connect to Server
Socket socket = new Socket("localhost",8090);
// Select keys
while (true) {
selector.select();
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while(iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
// check if key is valid
if(!key.isValid()) {
continue;
}
if(key.isAcceptable()) {
accept(key);
}else if(key.isReadable()) {
read(key);
}
}
}
}
}
My accept() and read() looks like this:
private void accept(SelectionKey key) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = server.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
}
private void read(SelectionKey key) {
SocketChannel channel = (SocketChannel) key.channel();
buffer.clear();
int n = -1;
n = channel.read(buffer);
if(n == -1) {
key.cancel();
channel.close();
}else{
//read to buffer
}
}
I have tried many ways but still cannot find out the problem. Thank you very much!
I am developing a server that is connected with many clients. I need to know when a client is disconnecting from server. So each client is sending a specific character to the server. If the character is not received after two seconds then I should disconnect the server from the client (releasing allocated resource for this client).
This is the main code of my server:
public EchoServer(int port) throws IOException {
this.port = port;
hostAddress = InetAddress.getByName("127.0.0.1");
selector = initSelector();
loop();
}
private Selector initSelector() throws IOException {
Selector socketSelector = SelectorProvider.provider().openSelector();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
InetSocketAddress isa = new InetSocketAddress(hostAddress, port);
serverChannel.socket().bind(isa);
serverChannel.register(socketSelector, SelectionKey.OP_ACCEPT);
return socketSelector;
}
private void loop() {
for (;true;) {
try {
selector.select();
Iterator<SelectionKey> selectedKeys = selector.selectedKeys()
.iterator();
while (selectedKeys.hasNext()) {
SelectionKey key = selectedKeys.next();
selectedKeys.remove();
if (!key.isValid()) {
continue;
}
// Check what event is available and deal with it
if (key.isAcceptable()) {
accept(key);
} else if (key.isReadable()) {
read(key);
} else if (key.isWritable()) {
write(key);
}
}
Thread.sleep(1000);
timestamp++;
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
The first question is that, whether the way that I used in order to recognizing online clients (sending specific message every second) is a good approach or not?
If it is good, how can I detect with SelectionKey is related to witch client and then how can I disconnect the key from server?
The first question is that, whether the way that I used in order to recognizing online clients (sending specific message every second) is a good approach or not?
Not in the case of an echo server. In many cases such as this, all you need is to recognize end of stream and connection failure appropriately.
how can I detect with SelectionKey is related to which client
The SelectionKey has a channel, the channel has a socket, and the Socket has a remote IP address:port. That's all you need.
and then how can I disconnect the key from server?
Close the channel when you get -1 from the read() method, or any IOException when reading or writing.
whether the way that I used in order to recognizing online clients (sending specific message every second) is a good approach or not?
Yes, it is called a heartbeat.
how can I detect with SelectionKey is related to witch client and then how can I disconnect the key from server?
You can attach an object which has all the information need regarding a channel. You include this when you register the channel.
I decided to make my UDPclient and UDPserver with java nio.
But I don't understand several things.
Here is the code
try {
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(false);
channel.connect(remote);
//monitoring
Selector selector = Selector.open();
//read write keys
channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
ByteBuffer buffer = ByteBuffer.allocate(1024*64);//number of bytes for channel
while (true) {
selector.select(60000);//number of channels I think
Set readyKeys = selector.selectedKeys();
if (readyKeys.isEmpty()) {
break;
}
else {
Iterator iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
if (key.isReadable( )) {
//read from buffer
channel.read(buffer);
}
if (key.isWritable()) {
//write to buffer
channel.write(buffer);
}
}
}
}
}
catch (IOException ex) {
System.err.println(ex);
}
If I write something in console the event in key.isWritable will occur? And if server sends something event isReadable will occur?
And I don't understand how to work with my events when for example user write "GETL" or "REGR"(my own methods).
The value you pass to select is a timeout not the number of channels.
You need to do
DatagramChannel channelFromKey = (DatagramChannel) key.channel();
not use channel
I don't understand what you mean by your own events. Read the Datagrams off the channel when that key is selected.
Iterator iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
if (key.isReadable( )) {
DatagramChannel channelFromKey =
(DatagramChannel) key.channel();
buffer.clear();
// This is a DatagramChannel receive a datagram as a whole
channelFromKey.receive(buffer);
}
If I write something in console the event in key.isWritable will
occur?
No. The only events that will occur are on the channels you have registered with the selector. You haven't registered any channel to do with the console, and you can't, because only network channels are SelectableChannels, so you have to reason to expect events originating from the console to turn up via the Selector.
And if server sends something event isReadable will occur?
Yes.
And I don't understand how to work with my events when for example user
write "GETL" or "REGR"(my own methods).
Nor do I. I don't even understand the question. The only events you will get from the selector are the ones that it defines, on the channels you have registered with it.