编辑:我删除了客户端代码,因为问题似乎出现在服务器上。
我实现了一个非常简单的netty echo服务器,类似于教程中的建议。
问题是当我尝试运行指向同一服务器的多个客户端时,服务器似乎一次只允许一个连接。例如,当我运行" telnet localhost 8080"并尝试使用来自两个不同客户端的echo服务器,第一个成功,而第二个失败(不回复)。此外,当我启动多个netty客户端时,我在服务器端看到仅从一个客户端端口接收消息 - 当该客户端完成并关闭其连接时,第二个客户端继续。有谁知道为什么会发生这种情况?这是使用netty 3.5.1。另外值得注意的是,即使没有很多输出,netstat在我的机器上运行速度也非常慢。这是我的服务器源代码(问题似乎在服务器上,因为我可以用telnet重现问题):
服务器:
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
public class Server {
public static void main(String[] args) {
ChannelFactory factory =
new NioServerSocketChannelFactory(
Executors.newSingleThreadExecutor(),
Executors.newSingleThreadExecutor());
ServerBootstrap bootstrap = new ServerBootstrap(factory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() {
return Channels.pipeline(new EchoServerHandler());
}
});
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
bootstrap.bind(new InetSocketAddress(8080));
}
private static AtomicInteger count = new AtomicInteger(0);
public static class EchoServerHandler extends SimpleChannelHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
Channel ch = e.getChannel();
int t = count.incrementAndGet();
if (t % 1000 == 0) {
System.out.println("server " + t + " " + e.getChannel());
}
ch.write(e.getMessage());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
e.getCause().printStackTrace();
Channel ch = e.getChannel();
ch.close();
}
}
}
更新:似乎我只能运行与服务器上的工作线程一样多的客户端(来自一些使用不同数量的客户端和不同的固定工作线程池大小的实验)。这是来自其中一个工作线程的jstack,卡在epollWait上(任何人都知道为什么?):
"New I/O worker #1" prio=10 tid=0x00007fdba801a000 nid=0x2b84 runnable [0x00007fdc296c2000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:228)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:81)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:87)
- locked <0x00000006b11732b0> (a sun.nio.ch.Util$2)
- locked <0x00000006b11732a0> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000006b1173080> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:98)
at org.jboss.netty.channel.socket.nio.SelectorUtil.select(SelectorUtil.java:52)
at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:209)
at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:35)
at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:102)
at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)