【发布时间】:2020-05-13 02:21:49
【问题描述】:
我修改了可用的示例代码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 错误。
但异常是 ConnectException。 我试图抓住它,但它没有进入 catch 块。
任何帮助将不胜感激。谢谢。 编辑: 我在窗户上工作。 我尝试更改 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
我对只有这么多客户才能连接感到困惑。
任何人都可以建议更好的参考来阅读客户端服务器 NIO。
编辑 2
正如 EJP 在他的评论中提到的,窗口 Backlog Queue 已满。 我修改了客户端代码以生成 100 个线程,然后休眠 5 秒,这样队列上没有太多负载,并且大部分连接都成功(但是在建立 10,000 个连接时仍然有些失败)。
【问题讨论】:
-
你用的是windows还是linux?