java nio select 的代码和 linux epoll 的代码看起来是一样的。不存在循环获取socket fd这样的东西,linux select代码片段确实使用了循环获取socket fd。
所以我的问题是,java nio select 和 linux epoll 是一样的吗?
java nio选择
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 电子投票
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选择
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是Java对非阻塞io的抽象。不同平台上会有不同的底层实现。在Linux上,它是使用epool实现的。在其他平台上,使用其他技术,例如kqueue。
这导致NIO与epoll非常相似,但是java希望你学习它的nio抽象,而不必关心底层实现。
关于java - java nio select 和 linux epoll 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57706441/