我修改了可用的示例代码here for Client and Server 我的客户:
public class Client {
public static void main(String[] args) {
int n=10000;
SocketTest [] st= new SocketTest[n];
for(int i=0;i<n;i++)
st[i]= new SocketTest("hi");
for(int i=0;i<n;i++)
new Thread(st[i]).start();
}
}
class SocketTest implements Runnable {
private String message = "";
private Selector selector;
private int i;
public SocketTest(String message){
this.message = message;
}
@Override
public void run() {
SocketChannel channel;
try {
selector = Selector.open();
channel = SocketChannel.open();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_CONNECT);
channel.connect(new InetSocketAddress("127.0.0.1", 8511));
while (!Thread.currentThread().isInterrupted()){
selector.select();
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while (keys.hasNext()){
SelectionKey key = keys.next();
keys.remove();
if (!key.isValid()) continue;
if (key.isConnectable()){
connect(key);
System.out.println("I am connected to the server");
}
if (key.isWritable()){
write(key);
}
if (key.isReadable()){
read(key);
}
}
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} finally {
close();
}
}
private void close(){
try {
selector.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void read (SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1000);
readBuffer.clear();
int length;
try{
length = channel.read(readBuffer);
} catch (IOException e){
System.out.println("Reading problem, closing connection");
key.cancel();
channel.close();
return;
}
if (length == -1){
System.out.println("Nothing was read from server");
channel.close();
key.cancel();
return;
}
readBuffer.flip();
byte[] buff = new byte[1024];
readBuffer.get(buff, 0, length);
//length=buff.length;
String fromserver = new String(buff,0,length,"UTF-8");
length = fromserver.length();
System.out.println("Server said: "+fromserver);
key.interestOps(SelectionKey.OP_WRITE);
}
private void write(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
i++;
message = "location now "+i;
try{
Thread.sleep(5000);
}
catch(InterruptedException ie)
{
System.out.println(""+ie);
}
channel.write(ByteBuffer.wrap(message.getBytes()));
// lets get ready to read.
key.interestOps(SelectionKey.OP_READ);
}
private void connect(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
try
{
if(!channel.finishConnect())
System.out.println("* Here *");
}
catch(ConnectException e)
{
System.out.println("BP 1");
e.printStackTrace();
//channel.close();
//key.cancel();
//return;
}
/*if (channel.isConnectionPending()){
while(!channel.ffinishConnect()){
System.out.println("not connected");
}
}*/
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_WRITE);
}
}
我通过创建多个线程在同一台机器上创建多个客户端。
线程数不是由n的值决定的。
当我运行少量客户端时,我遇到没有问题但是一旦我用n运行500即500个客户端线程,一些线程运行正常但在某些我遇到这个:
java.net.ConnectException: Connection refused: no further information
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
at sun.nio.ch.SocketChannelImpl.finishConnect(Unknown Source)
at SocketTest.connect(Client.java:143)
at SocketTest.run(Client.java:61)
第143行是:
if(!channel.finishConnect())
因此,当我阅读此方法的文档时,它会抛出:
NoConnectionPendingException - 如果未连接此频道且尚未启动连接操作。
ClosedChannelException - 如果此频道已关闭。
AsynchronousCloseException - 如果另一个线程在连接操作正在进行时关闭此通道。
ClosedByInterruptException - 如果另一个线程在连接操作正在进行时中断当前线程,从而关闭通道并设置当前线程的中断状态。
IOException - 如果发生其他一些I / O错误。
但Exception是ConnectException。 我试着捕捉它,但它没有进入捕获区。
任何帮助将不胜感激。谢谢。 编辑: 我在Windows上工作。 我尝试更改n的值,看看有多少客户端被创建,有多少导致异常,这些是结果(我知道等待更多时间后,每次测试将允许更多的开放套接字,因为每个测试scokets将在TIME_WAIT之后发布):
n clients connected(by keeping a count at server)
1000 522
2000 568
3000 626
4000 600 (maybe I gave less time before successive runs)
5000 1345
6000 1389
我很困惑,只有这么多客户才能连接起来。
任何人都可以建议更好地参考读取Client Server NIO。
编辑2
正如EJP在评论中提到的,Backlog Queue窗口已经满了。 我修改了客户端代码以生成100个线程,然后休眠5秒,这样队列上没有太多负载,并且大部分连接都成功(但是当仍然有10,000个连接时,有些仍然失败)。
答案 0 :(得分:3)
ConnectException: connection refused
表示没有任何内容正在侦听您尝试连接的IP:端口,或者在某些平台上,服务器的监听 - 备份日志队列已填满。如果它被抛出并且你正确地抓住它,你肯定会抓住它。您必须扩展实际发生的事情以及实际捕获代码的内容以获得进一步的帮助。
但是你还有很多其他问题:
private void connect(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
try
{
if(!channel.finishConnect())
System.out.println("* Here *");
此时,如果finishConnect()
返回false,则应返回。您应该不通过并重新注册OP_WRITE.
的频道。连接仍然未决。打印"* Here *"
也是徒劳的。尝试打印有意义的东西。
}
catch(ConnectException e)
{
System.out.println("BP 1");
e.printStackTrace();
//channel.close();
此时你应该关闭频道。对人类或野兽没有任何用处。
//key.cancel();
关闭频道取消密钥。删除遇到的任何地方。
//return;
如上所述,你当然应该回归。
}
/*if (channel.isConnectionPending()){
while(!channel.ffinishConnect()){
System.out.println("not connected");
}
}*/
摆脱这种烦恼。在非阻塞模式下旋转循环永远不合适。甚至不要把它留在周围作为评论:一些白痴可能会在以后出现并将其放回去。
channel.configureBlocking(false);
频道已处于非阻止模式。否则你就不会在这里。删除。
channel.register(selector, SelectionKey.OP_WRITE);
另一种方法是key.interestOps(SelectionKey.OP_WRITE);
在网络代码中睡觉实际上是浪费时间。它没有解决任何问题。
您假设write()
完全成功,并且您忽略了它返回的计数。
您使用质量相当差的参考资料:
write()
的相同评论如上所述。flip()
不像重置&#39;。ByteBuffer,
,但无论如何,每次阅读分配ByteBuffer
都是不好的做法。ServerSocketChannel.accept()
可以返回null.
Map
。Thread.interrupted()
。IOException
,因此无需关闭所有内容。尝试找到更好的东西。
答案 1 :(得分:0)
我相信你获得500个主题的ConnectException
并非来自SocketTest.connect()
。它可能来自任何其他IO方法。
要快速修复(并说服自己),您可以在主ConnectException
块中明确捕捉try-catch
,如下所示:
try {
// connect, write, and read ...
} catch (ConnectException ce) { // <-- catch the more specific Exception first
System.out.println("You caught a ConnectException.");
} catch (IOException e1) { // <-- you originally only caught this
// TODO Auto-generated catch block
e1.printStackTrace();
} finally {
至于为什么会发生这种情况,我可以告诉你,我目前正在使用数百个线程来测试SOAP服务。我也得到了所有地方的连接断开,所以也许可以预期这么多的并发线程。
答案 2 :(得分:0)
尝试使用命令进行Telnet-
telnet [host IP] [port]
问题可能与防火墙阻止端口有关。