The code for java nio select and the code for linux epoll look the same. There is no such thing as loop to get socket fd, and the linux select code fragment does use loop to get socket fd.
So my question is, is the java nio select and linux epoll the same way?
java nio select
while (true) {
try {
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
selectionKeys.forEach((selectionKey) -> {
final SocketChannel client;
try {
if (selectionKey.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel();
client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
String key = "[" + UUID.randomUUID().toString() + "]";
clientMap.put(key, client);
} else if (selectionKey.isReadable()) {
client = (SocketChannel) selectionKey.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int count = client.read(readBuffer);
if (count > 0) {
//...
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
});
selectionKeys.clear();
} catch (Exception e) {
e.printStackTrace();
}
}
linux e poll
for (;;) {
nfds = epoll_wait(epfd, events, 20, 500);
for (i = 0; i < nfds; ++i) {
if (events[i].data.fd == listenfd)
{
connfd = accept(listenfd, (sockaddr *) &clientaddr, &clilen);
if (connfd < 0) {
perror("connfd<0");
exit(1);
}
//setnonblocking(connfd);
char *str = inet_ntoa(clientaddr.sin_addr);
ev.data.fd = connfd;
ev.events = EPOLLIN | EPOLLET;
epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
} else if (events[i].events & EPOLLIN)
{
cout << "EPOLLIN" << endl;
if ((sockfd = events[i].data.fd) < 0)
continue;
if ((n = read(sockfd, line, MAXLINE)) < 0) {
if (errno == ECONNRESET) {
close(sockfd);
events[i].data.fd = -1;
} else
std::cout << "readline error" << std::endl;
} else if (n == 0) {
close(sockfd);
events[i].data.fd = -1;
}
line[n] = '/0';
cout << "read " << line << endl;
ev.data.fd = sockfd;
ev.events = EPOLLOUT | EPOLLET;
//epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
} else if (events[i].events & EPOLLOUT)
{
sockfd = events[i].data.fd;
write(sockfd, line, n);
ev.data.fd = sockfd;
ev.events = EPOLLIN | EPOLLET;
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
}
}
}
linux select
for (;;) {
rset = allset; /* structure assignment */
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (FD_ISSET(listenfd, &rset)) /* new client connection */
{
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
#ifdef NOTDEF
printf("new client: %s, port %d\n",
inet_ntop(AF_INET, &cliaddr.sin_addr, 4, NULL),
ntohs(cliaddr.sin_port));
#endif
for (i = 0; i < FD_SETSIZE; i++)
if (client[i] < 0) {
client[i] = connfd; /* save descriptor */
break;
}
if (i == FD_SETSIZE) {
printf("too many clients");
exit(0);
}
FD_SET(connfd, &allset); /* add new descriptor to set */
if (connfd > maxfd)
maxfd = connfd; /* for select */
if (i > maxi)
maxi = i; /* max index in client[] array */
if (--nready <= 0)
continue; /* no more readable descriptors */
}
for (i = 0; i <= maxi; i++) /* check all clients for data */
{
if ((sockfd = client[i]) < 0)
continue;
if (FD_ISSET(sockfd, &rset)) {
if ((n = read(sockfd, buf, MAXLINE)) == 0)/* connection closed by client */
{
close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
} else
write(sockfd, buf, n);
if (--nready <= 0)
break; /* no more readable descriptors */
}
}
}
JAVA NIO is Java's abstraction of non-blocking io. There will be different underlying implementations on different platforms. On Linux, it is implemented using epool. On other platforms, other technologies such as kqueue are used.
This causes NIO to be very similar to epoll, but java wants you to learn its nio abstraction, without having to care about the underlying implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With