我正在尝试基于非阻塞NIO消息开发自己的通信库。我已经阅读了1000篇关于它的教程和书中的章节,我认为最后我有了一些可以在几乎没有同时连接的情况下工作的东西。但是当我在服务器端有很多连接共存时,我遇到了一些问题。
我有4个私有方法的典型选择器实现:accept、finishConnect、read和write。我的问题在于前两个:接受和完成连接。
当客户端打开一个新的套接字,并且一个可接受的键唤醒选择器时,将执行以下代码。
private void accept(SelectionKey key) {
try {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
LOGGER.debug("Socket " + sc.hashCode() + "-" + sc.socket().toString() + " connexion completed");
changeInterest(sc, SelectionKey.OP_READ);
eventManager.addEvent(new ConnectionEstablished(sc));
} catch (Throwable e) {
NIOException ne = new NIOException(NIOException.ErrorType.ACCEPTING_CONNECTION, e);
eventManager.addEvent(new ErrorEvent(null, ne));
}
}
在客户端,我有一个连接方法的实现,一旦服务器处理其可接受的套接字密钥,就会调用该方法。
private void finishConnect(SelectionKey key) {
SocketChannel sc = (SocketChannel) key.channel();
try {
if (sc.finishConnect()) {
eventManager.addEvent(new ConnectionEstablished(sc));
LOGGER.debug("Socket " + sc.hashCode() + "-" + sc.socket().toString() + " connection finished");
} else {
LOGGER.debug("REFUSED " + sc + " - " + sc.socket().toString());
refusedConnection(sc, null);
key.cancel();
}
} catch (Exception e) {
refusedConnection(sc, e);
key.cancel();
}
}
问题是,当我创建一些被接受的连接时,客户端执行finishConnect消息(我可以看到使用的端口建立的套接字连接)。但是我在服务器端找不到这个连接接受,没有使用这些端口的连接完成日志消息!!
我怀疑ssc之间可能会出现异常。accept()和日志调用,所以我添加了一些额外的日志消息,以检查哪个指令正在破坏所有内容。对于进入accept方法的所有键,序列都已完成。
如果我甚至看不到日志上的任何错误消息,这怎么可能呢?
编辑:我对一次打开的套接字的数量做了一些测试。当客户端开始运行时,服务器上只有一个openSocket:服务器套接字。之后,它有多达200个同时打开的套接字,在客户端执行结束时,服务器会回到1个打开的套接字。我想它们永远不会被计算在内
到目前为止,我已经做了一个变通方法,可以监控节点上共存连接的数量,并延迟新连接的接受,直到该数量减少到给定的阈值。然而,我想知道出了什么问题。
谢谢你的帮助。
正如EJP所说,问题出在待办事项队列上。我使用bind(SocketAddress local)方法绑定ServerSocketChannel。
当套接字请求到达JVM时,它会进入待办事项队列,并在那里等待,直到侦听器触发接受相应密钥的过程。实际问题在于这个队列的大小,使用bind方法,它最多可以存储50个连接。
当连接请求达到峰值时,队列会出现溢出,其中一些请求会丢失。为了避免这种情况发生,方法bind(SocketAddress local,int backlog)允许更改队列的容量并增加它。
另一方面,在非阻塞模式下工作时,客户端节点上的选择器不需要接受连接来处理OP_CONNECT密钥。接收SYN-ACK TCP消息将触发选择器中的相应键。
由于积压工作队列的存在,在执行accept()
之前完成大量客户机连接是完全合适的。所以这里没有需要解决的实际问题。
但是您是否执行过accept()
方法?这就是你需要调查的问题。
我最近开始尝试使用JavaSockets类在服务器和客户机之间创建双向连接。当我使用客户机套接字地址作为但是当我在 客户端套接字显示连接是通过测试返回true。 然而,在服务器端,代码似乎并没有向前推进 我应该提供代码还是问题明确? 编辑:更多信息。无论我的防火墙处于什么状态,使用外部ip地址从我自己的电脑上远程登录都是有效的。当防火墙打开时,java客户端代码不起作用,抛出 当防火墙关闭时,使用
我刚刚开始使用Sockets,对于我当前的项目,我需要能够从客户端控制我的程序,但是如果我的项目合作伙伴想同时使用他的客户端,服务器不会向他发送“您已连接”消息,如连接类所示。所以我假设服务器不同时接受多个客户端。我尝试过使用类Connection的Thread,但这也不会向第二个客户端发送消息“您已连接”。我在这里做错了什么? 这是我用来同时连接多个用户的线程: 编辑:附加信息 在第一个客户端连
我正在学习套接字编程,服务器套接字让我感到困惑。我为服务器套接字写了两个场景,请看一下: null 如果我的一个假设是正确的,那会回答下面的问题吗?或者,我的两种设想都是错误的。如果你能指导我找到正确的答案,或者至少是一些相关的文本来学习,我将非常感谢。
我正在尝试创建一个非常基本的JavaFTP服务器。 处理传入套接字、接受它并将其转换为客户机线程的代码似乎工作得很好,但由于某些原因,当我尝试发送欢迎消息时,数据似乎没有到达客户机。 我在控制台中看到它正在运行并试图发送欢迎消息,但是FileZilla(我用来连接的FTP客户端)通常位于: === 编辑 欢迎信息非常基本:发送(“220欢迎使用FTP服务器”); 我试图只包含相关的代码,因为在这里
我试图用java实现一个客户端服务器,在这里我读取客户端中的输入并在服务器中执行UperCase,然后返回客户端并打印UperCase。我使用ObjectOutputStream和ObjectInputStream进行读写,但是当我在客户机中键入一个msg时,程序会显示以下错误: Digite uma msg casa java.io.eofexception位于java.io.datainput
问题内容: 我有一个带有两个服务器端进程的程序。一台服务器只是将ArrayList发送给客户端。另一个服务器首先从客户端获取一个字符串,然后找到与该ID对应的正确记录,然后将记录发回。 我在第二个服务器进程中遇到问题。请参阅下面的println语句,其中显示“卡在此处”。那就是程序挂起的地方。 客户端: 问题答案: 您需要在两端的ObjectInputStream之前创建ObjectOutputS