首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么我的NIO客户端到服务器连接中断?

为什么我的NIO客户端到服务器连接中断?
EN

Stack Overflow用户
提问于 2016-05-10 01:15:51
回答 1查看 961关注 0票数 0

目前,我在非阻塞模式下使用NIO库编写了一个桌面服务器。您可以找到完整的服务器项目这里。我还为测试目的创建了一个非阻塞的NIO客户端。您可以找到那个项目这里。最后,服务器应该用于android即时消息应用程序。我的客户端和服务器都是基于发送“数据包”来进行通信的想法。我的意思是,数据包类的引用被打包到字节缓冲区中,并通过套接字通道发送。然后,在另一边反序列化并执行它们。

我当前的问题:我的测试客户端似乎在连接到服务器时放弃了它的连接。我知道问题是客户端的,因为当我使用telnet通过命令行连接到服务器时,连接不会丢失。奇怪的是,服务器正在打印到它的连接已经建立,但从来没有说连接已经丢失/终止时,客户端放弃连接。

这是处理所有nio网络的客户机类..。

代码语言:javascript
复制
 import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.baiocchi.enigma.client.test.Engine;
import org.baiocchi.enigma.client.test.databundle.DataBundle;
import org.baiocchi.enigma.client.test.packet.Packet;
import org.baiocchi.enigma.client.test.ui.LogType;
import org.baiocchi.enigma.client.test.ui.Logger;

public class Client extends Thread {

    private boolean running;
    private final int port;
    private SocketChannel connection;
    private final ByteBuffer buffer;
    private Selector selector;
    private List<DataBundle> pendingDataBundleQue;

    public Client(int port) {
        this.port = port;
        pendingDataBundleQue = new LinkedList<DataBundle>();
        buffer = ByteBuffer.allocate(8192);
        try {
            selector = initiateSelector();
            connection = initiateConnection();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private Selector initiateSelector() throws IOException {
        return SelectorProvider.provider().openSelector();
    }

    private SocketChannel initiateConnection() throws IOException {
        SocketChannel connection = SocketChannel.open();
        connection.configureBlocking(false);
        connection.connect(new InetSocketAddress("localhost", port));
        connection.register(selector, SelectionKey.OP_CONNECT);
        return connection;
    }

    public SocketChannel getConnection() {
        return connection;
    }

    @Override
    public void start() {
        running = true;
        super.start();
    }

    public void addToPendingDataBundleQue(DataBundle bundle) {
        synchronized (pendingDataBundleQue) {
            pendingDataBundleQue.add(bundle);
        }
    }

    @Override
    public void run() {
        while (running) {
            System.out.println("loop");
            try {
                synchronized (pendingDataBundleQue) {
                    System.out.println("Checking for que changes.");
                    if (!pendingDataBundleQue.isEmpty()) {
                        System.out.println("Found que change.");
                        SelectionKey key = connection.keyFor(selector);
                        key.interestOps(SelectionKey.OP_WRITE);
                    }
                }
                System.out.println("Selecting keys");
                selector.select();
                System.out.println("Creating selected keys list.");
                Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
                while (selectedKeys.hasNext()) {
                    System.out.println("scrolling through list");
                    SelectionKey key = (SelectionKey) selectedKeys.next();
                    selectedKeys.remove();
                    if (!key.isValid()) {
                        System.out.println("invalid");
                        continue;
                    } else if (key.isConnectable()) {
                        System.out.println("connect");
                        establishConnection(key);
                    } else if (key.isReadable()) {
                        System.out.println("read");
                        readData(key);
                    } else if (key.isWritable()) {
                        System.out.println("write");
                        writeData(key);
                    }
                }
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Broke loop");
    }

    private void writeData(SelectionKey key) throws IOException {
        synchronized (pendingDataBundleQue) {
            SocketChannel connection = (SocketChannel) key.channel();
            for (DataBundle bundle : pendingDataBundleQue) {
                System.out.println("sent packet");
                connection.write(bundle.getBuffer());
            }
            pendingDataBundleQue.clear();
            if (pendingDataBundleQue.isEmpty()) {
                Logger.write("All packets sent.", LogType.CLIENT);
                connection.keyFor(selector).interestOps(SelectionKey.OP_READ);
            }
        }
    }

    private void readData(SelectionKey key) throws IOException, ClassNotFoundException {
        buffer.clear();
        int byteCount;
        try {
            byteCount = connection.read(buffer);
        } catch (IOException e) {
            Logger.writeException("Connenction closed.", LogType.CLIENT);
            connection.close();
            key.cancel();
            return;
        }
        if (byteCount == -1) {
            Logger.writeException("Connection error. Attempting to terminate connection.", LogType.CLIENT);
            key.channel().close();
            key.cancel();
        }
        Engine.getInstance().getPacketProcessor().processData(buffer);
    }

    private void establishConnection(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        try {
            if (channel.finishConnect()) {
                Logger.write("Connection established.", LogType.CLIENT);
                key.interestOps(SelectionKey.OP_READ);
            }
        } catch (IOException e) {
            Logger.write("Failed to establish connection.", LogType.CLIENT);
            key.channel().close();
            key.cancel();
            return;
        }
    }

}

处理所有服务器网络的服务器类在这里。

代码语言:javascript
复制
    package org.baiocchi.enigma.server.network;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.ArrayList;
import java.util.Iterator;

import org.baiocchi.enigma.server.Engine;
import org.baiocchi.enigma.server.databundle.DataBundle;
import org.baiocchi.enigma.server.ui.components.logger.LogType;
import org.baiocchi.enigma.server.ui.components.logger.Logger;

public class Server extends Thread {

    private boolean running;
    private final int port;
    private ServerSocketChannel server;
    private final ByteBuffer buffer;
    private Selector selector;
    private ArrayList<DataBundle> pendingDataBundleQue;

    public Server(int port) {
        this.port = port;
        buffer = ByteBuffer.allocate(8192);
        pendingDataBundleQue = new ArrayList<DataBundle>();
        try {
            server = ServerSocketChannel.open().bind(new InetSocketAddress("localhost", port));
            server.configureBlocking(false);
            selector = SelectorProvider.provider().openSelector();
            server.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void start() {
        running = true;
        super.start();
    }

    public void terminateConnection(SocketChannel channel) {
        SelectionKey key = channel.keyFor(selector);
        try {
            key.channel().close();
            key.cancel();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void addToPendingPacketQue(DataBundle bundle) {
        synchronized (pendingDataBundleQue) {
            pendingDataBundleQue.add(bundle);
        }
    }

    @Override
    public void run() {
        while (running) {
            try {
                synchronized (pendingDataBundleQue) {
                    if (!pendingDataBundleQue.isEmpty()) {
                        for (DataBundle bundle : pendingDataBundleQue) {
                            SelectionKey key = bundle.getChannel().keyFor(selector);
                            key.interestOps(SelectionKey.OP_WRITE);
                        }
                    }
                }
                selector.select();
                Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
                while (selectedKeys.hasNext()) {
                    SelectionKey key = (SelectionKey) selectedKeys.next();
                    selectedKeys.remove();
                    if (!key.isValid()) {
                        continue;
                    } else if (key.isAcceptable()) {
                        acceptConnection(key);
                    } else if (key.isReadable()) {
                        readData(key);
                    } else if (key.isWritable()) {
                        writeData(key);
                    }
                }
            } catch (IOException | ClassNotFoundException e) {
                Logger.writeException("Internal server error.", LogType.SERVER);
                Logger.writeException(e.getMessage(), LogType.SERVER);
            }
        }
    }

    private void writeData(SelectionKey key) throws IOException {
        DataBundle bundle = null;
        for (DataBundle b : pendingDataBundleQue) {
            if (b.getChannel().equals((SocketChannel) key.channel())) {
                bundle = b;
                break;
            }
        }
        if (bundle == null) {
            Logger.writeException("Couldn't find out bound packet in list.", LogType.SERVER);
            return;
        }
        SocketChannel connection = bundle.getChannel();
        connection.write(bundle.getBuffer());
        connection.keyFor(selector).interestOps(SelectionKey.OP_READ);
        pendingDataBundleQue.remove(bundle);
    }

    private void readData(SelectionKey key) throws IOException, ClassNotFoundException {
        SocketChannel channel = (SocketChannel) key.channel();
        buffer.clear();
        int byteCount;
        try {
            byteCount = channel.read(buffer);
        } catch (IOException e) {
            Logger.writeException("Connenction terminated.", LogType.SERVER);
            channel.close();
            key.cancel();
            return;
        }
        if (byteCount == -1) {
            Logger.writeException("Connection error. Terminating connection.", LogType.SERVER);
            key.channel().close();
            key.cancel();
            return;
        }
        Engine.getInstance().getPacketProcessor().processData(buffer, channel);
    }

    private void acceptConnection(SelectionKey key) throws IOException {
        ServerSocketChannel channel = (ServerSocketChannel) key.channel();
        SocketChannel connection = channel.accept();
        connection.configureBlocking(false);
        connection.register(selector, SelectionKey.OP_READ);
        Logger.write("Connection established.", LogType.SERVER);
    }

}

提前谢谢你!

EN

回答 1

Stack Overflow用户

发布于 2016-05-10 02:13:06

这里没有证据表明客户已经放弃了连接。如果有,这些块中的一个将在服务器上执行:

代码语言:javascript
复制
    try {
        byteCount = channel.read(buffer);
    } catch (IOException e) {
        Logger.writeException("Connenction terminated.", LogType.SERVER);
        channel.close();
        key.cancel();
        return;
    }
    if (byteCount == -1) {
        Logger.writeException("Connection error. Terminating connection.", LogType.SERVER);
        key.channel().close();
        key.cancel();
        return;
    }

我的结论是,客户端根本没有放弃连接。

我注意到,您有一个名为Logger.writeException()的方法,您从未使用该方法来记录异常,并且您的日志消息是背靠背的:catch (IOException )表示一个连接错误,您应该在其上记录实际的异常,而readBytes == -1则表示'connection and‘,这不是一个错误。

我还注意到客户端相应代码中缺少一个return

关闭通道会取消密钥。你不需要自己取消。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37127787

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档