java - 具有 NIO channel 的简单客户端-服务器程序

标签 java buffer echo nio socketchannel

已解决 如果有人感兴趣,我可以用正确的数据编辑这篇文章。只需发表评论即可。

<小时/>

作为我的任务,我必须使用非阻塞 channel 和选择器创建一个简单的服务器和客户端。 基本上它应该回显客户端编写的消息或添加两个数字(也由客户端提供)。

我的问题是在服务器即将回显消息时出现错误。 我检查了 msg 是否到达 writeResponse 方法,并且确实如此。这就是问题开始的地方。

先谢谢大家了!

我得到的错误:

   java.io.IOException: An existing connection was forcibly closed by the remote host
at sun.nio.ch.SocketDispatcher.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:218)
at sun.nio.ch.IOUtil.read(IOUtil.java:191)
at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:359)
at SimpleServer.serviceRequest(SimpleServer.java:89)
at SimpleServer.serviceConnections(SimpleServer.java:61)
at SimpleServer.<init>(SimpleServer.java:35)
at SimpleServer.main(SimpleServer.java:141)

服务器:

  public class SimpleServer {

private ServerSocketChannel ssc = null; //for multiplexing
private Selector selector = null; //monitors channels

private static Charset charset = Charset.defaultCharset();//encoding
private static final int BSIZE = 1024;//buffer size

private ByteBuffer bbuf = ByteBuffer.allocate(BSIZE);
private StringBuffer reqString = new StringBuffer();

public SimpleServer(String host, int port) {
    try {           
        ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);
        ssc.socket().bind(new InetSocketAddress(host, port));           
        selector = Selector.open(); //selector initiation           
        ssc.register(selector,  SelectionKey.OP_ACCEPT);  //registering communication channel           
    } catch(Exception exc) {
        exc.printStackTrace();
        System.out.println(1);
    }

    System.out.println("Server started and is ready for requests");
    serviceConnections();
}//constructor

private void serviceConnections() {     
    boolean serverIsRunning = true;     
    while(serverIsRunning) {
        try {

            selector.select();//waits for answer from selector              
            Set<SelectionKey> keys = selector.selectedKeys(); //set of keys
            Iterator<SelectionKey> iter = keys.iterator(); //iterration throught set of keys

            while(iter.hasNext()) {
                SelectionKey key = (SelectionKey) iter.next(); //obtain key
                iter.remove(); //remove, because we'd get it again

                if(key.isAcceptable()) {
                    SocketChannel cc = ssc.accept();//obtaining channel for communication
                    cc.configureBlocking(false);
                    cc.register(selector, SelectionKey.OP_READ); //registering selector for monitoring
                    continue;
                }

                if(key.isReadable()) { //channel with readable data
                    SocketChannel cc = (SocketChannel) key.channel();
                    serviceRequest(cc);
                    continue;
                }                   
            }//while loop

        } catch(Exception exc) {
            exc.printStackTrace();
            continue;
        }
    }//outer while loop     
}//serviceCconnection method    

private void serviceRequest(SocketChannel sc) {
    if(!sc.isOpen()) return;

    reqString.setLength(0);
    bbuf.clear();

    try {
        readLoop:
            while (true) {
                int n = sc.read(bbuf);                  
                if(n > 0) {
                    bbuf.flip();//set limit, return to beginning
                    CharBuffer cbuf = charset.decode(bbuf);
                    while(cbuf.hasRemaining()) {
                        char c = cbuf.get();
                        if (c == '\r' || c == '\n') break readLoop;
                        reqString.append(c);
                    }
                }
            }//while loop

    String[] req = reqString.toString().split(" ");
    String cmd = req[0];

    if (cmd.equals("bye")) { 
          sc.close();                      
          sc.socket().close();
      }
    else if(cmd.equals("echo"))

        writeResp(sc, reqString.toString());

    else if(cmd.equals("add"))
        writeResp(sc, Integer.parseInt(req[1]),Integer.parseInt( req[2]));
    } catch (Exception exc) {                  
        exc.printStackTrace();
        try { sc.close();
              sc.socket().close();
        } catch (Exception e) {}
    }
}//serviceRequest   

//overloaded methods
public void writeResp(SocketChannel sc, String msg) throws IOException {
    System.out.println(msg);
    ByteBuffer cbuf = charset.encode(CharBuffer.wrap(msg));
    cbuf = ByteBuffer.allocate(1024);
    cbuf.put(msg.getBytes());
    cbuf.rewind();
     sc.write(cbuf);
}//writeResp method

public void writeResp(SocketChannel sc, int i, int j) throws IOException, NumberFormatException {
    int ans = i + j;
    String resp = Integer.toString(ans);
    ByteBuffer cbuf = charset.encode(CharBuffer.wrap(resp));
    sc.write(cbuf);
}//write Resp method

public static void main(String[] args) {
    try {
        String host = "localhost";
        int port = 9998;
                new SimpleServer(host, port);
    } catch(Exception exc) {
        exc.printStackTrace();
        System.out.println(1);
    }
}//main
}//class

我的客户:

 public class SimpleClient {

private SocketChannel sc;   
private static Charset charset;
private StringBuffer reqString = new StringBuffer();
private ByteBuffer bb;
String msg;

public SimpleClient(String host, int port) throws IOException, InterruptedException {
    try {

        sc = SocketChannel.open();
        sc.configureBlocking(false);
        sc.connect(new InetSocketAddress(host, port));
        System.out.println("Connecting to the server...");

        while(!sc.finishConnect()) {
            System.out.println("Connection is being established...");
        }
    } catch (IOException exc) {
        System.out.println("IO exception");
        System.exit(1);
    }
    System.out.println("Connection Established!");

    makeRequest("echo Test input stream\n");
    Thread.sleep(500);
    readRequest();      
}//constructor

private void makeRequest(String req) throws IOException {
    System.out.println("Request: " + req);      
     bb = ByteBuffer.allocate(1024);
     bb.put(req.getBytes());
     bb.rewind();
     sc.write(bb);  
}//makeRequest method

public void readRequest() throws IOException, InterruptedException {        

    reqString.setLength(0);
    bb.clear();

    try {
        readLoop:       
        while (true) {      
            bb.clear();
            int readBytes = sc.read(bb);
            if(readBytes == 0){
                System.out.println("waiting for data");
            continue;
            }
            else if(readBytes == -1) {
                System.out.println("Server not responding");
                break;
            }
            else {
                bb.flip();
                CharBuffer cbuf = charset.decode(bb);
                while(cbuf.hasRemaining()) {
                    char c = cbuf.get();
                    if (c == '\r' || c == '\n') break readLoop;
                    reqString.append(c);
                }
            }
        }//while loop

    System.out.println(reqString.toString());
        } catch( Exception exc) {//while loop
            exc.printStackTrace();
        }
}//readRequest method   

public static void main(String[] args)  {
    try {
    new SimpleClient("localhost", 9998);
    }catch (IOException exc) {
        exc.printStackTrace();
    }catch(InterruptedException exc) {
        exc.printStackTrace();
    }
}//main method  
 }//class

最佳答案

如果 read() 返回 -1,并不意味着“服务器没有响应”。这意味着对等方已关闭连接,您也应该这样做。相反,您根本没有关闭它,因此操作系统会进行重置,因此您的服务器会收到此异常。

关于java - 具有 NIO channel 的简单客户端-服务器程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22424117/

相关文章:

c++ - C++中的高速缓冲

java - Runtime.getRuntime().exec ("C:\cygwin\bin\bash.exe") 没有可读取的输入

java - 许多 jbutton 具有相同的 onkeypress 功能

java - 使用java中的自签名证书连接到websocket

OpenGL:VAO 和 VBO 是否适用于大型多边形渲染任务?

json - 使用 Bash 编写 JSON 文件的最有效方法是什么?

java - 如何打印数组列表中的每个对象并正确计算它们的数量?

node.js - Sharp无法读取文件缓冲区

php - echo 和 (var_dump 或 print_r) 在 laravel 对象上显示完全不同的内容

WordPress 短代码中的 PHP Echo