字节缓冲区的TCP响应损坏

时间:2018-08-26 22:10:20

标签: java tcp serversocket socketchannel

我有Tcp服务器

public class SomeServer implements Runnable{


    private static final int BUFFER_SIZE = 4096;
    private Selector selector;
    private int port;
    private boolean runserver = true;
    private ServerSocketChannel mySocketChannel;
    private ServerSocket serverSocket;

    public SomeServer(int port) {
        this.port = port;
    }


    @Override
    public void run() {
        startServer();
    }

    private void startServer() {
        try {
            selector = Selector.open();
            InetAddress hostIP = InetAddress.getByName("127.0.0.1");
            mySocketChannel = ServerSocketChannel.open();
            serverSocket = mySocketChannel.socket();
            InetSocketAddress address = new InetSocketAddress(hostIP, port);
            log.info("Setting up SomeServer with on {} with port {} ", hostIP, port);
            serverSocket.bind(address);
            mySocketChannel.configureBlocking(false);
            int ops = mySocketChannel.validOps();
            mySocketChannel.register(selector, ops, null);
            while (runserver) {
                log.info("Server running");
                selector.select();
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> i = selectedKeys.iterator();

                while (i.hasNext()) {
                    SelectionKey key = i.next();

                    if (key.isAcceptable()) {
                        processAcceptEvent(mySocketChannel, key);
                    } else if (key.isReadable()) {
                        processReadEvent(key);
                    }
                    i.remove();
                }
            }

        } catch (Exception e) {
            log.error("Something gone wrong in SomeServer {}", e);
        }
    }

    private void processAcceptEvent(ServerSocketChannel mySocket, SelectionKey key) throws IOException {
        log.info("Connection Accepted...");
        // Accept the connection and make it non-blocking
        SocketChannel myClient = mySocket.accept();
        myClient.configureBlocking(false);
        // Register interest in reading this channel
        myClient.register(selector, SelectionKey.OP_READ);
    }

    private void processReadEvent(SelectionKey key) throws Exception {
        log.info("Inside processReadEvent...");
        // create a ServerSocketChannel to read the request
        SocketChannel myClient = (SocketChannel) key.channel();

        ByteBuffer myBuffer = ByteBuffer.allocate(BUFFER_SIZE);

        myBuffer.order(ByteOrder.BIG_ENDIAN);
        int radBytes= myClient.read(myBuffer);
        if(radBytes ==-1)
            return; //means connection is closed

        ByteBuffer responseBuffer = clone(execute(myBuffer));

        if(responseBuffer ==null){
            return;
        }
        int byteswritten = myClient.write(responseBuffer);
        log.info("bytesWritten...: {}", byteswritten);
    }

public ByteBuffer execute(ByteBuffer requestBuffer) throws Exception {
    final CharsetEncoder myEncoder = Charset.forName("ISO-8859-1").newEncoder();
    final byte END_OF_MESSAGE_BYTE = (byte) 0x2b;
    CharsetDecoder myDecoder = Charset.forName("ISO-8859-1").newDecoder();

    //Process Request
    final ByteBuffer processBuffer = clone(requestBuffer);
    // processBuffer.flip();
    int bufferSize = processBuffer.getInt();
    String request = myDecoder.decode(processBuffer).toString().trim();
    int requestLength=request.length();
    if(requestLength<8){
        log.info("Connection closed ");
        return null;
    }
    String firstName = request.substring(0,8);
    int requestBodyLength= requestLength-firstName.length();
    String command = request.substring(8,requestLength-1);

    processBuffer.flip();
    //Build-Response
    processBuffer.clear();
    String response="some response";
    int responselength = response.length()+firstName.length()+4;
    processBuffer.putInt(responselength);
    processBuffer.put(myEncoder.encode(CharBuffer.wrap(firstName)));
    processBuffer.put(myEncoder.encode(CharBuffer.wrap(response)));
    processBuffer.put(END_OF_MESSAGE_BYTE);
    processBuffer.flip();

    return processBuffer;
}

public static ByteBuffer clone(ByteBuffer original) {
    if(original == null)
        return null;
    ByteBuffer clone = ByteBuffer.allocate(original.capacity());
    original.rewind();//copy from the beginning
    clone.put(original);
    original.rewind();
    clone.flip();
    return clone;
}


}

发送一些消息,但返回一些回复

客户端:读取响应

     public class Mycleint {

 priavte SocketCahnnel mySocket;
 priavte String name;
 final byte END_OF_MESSAGE_BYTE = (byte) 0x2b;

public Mycleint (String name , InetSocketAddress inetAddress){
        this.name=name;
        mySocket = SocketChannel.open();
        mySocket.connect(inetAddress);

}

 private String sendRequest(String request) throws IOException {
            final CharsetEncoder myEncoder = Charset.forName("ISO-8859-1").newEncoder();
            int requestLength = 12 + request.length() + 1;
            ByteBuffer buffer = ByteBuffer.allocate(requestLength);
            buffer.order(ByteOrder.BIG_ENDIAN);
            buffer.putInt(requestLength);
            buffer.put(myEncoder.encode(CharBuffer.wrap(name)));
            buffer.put(myEncoder.encode(CharBuffer.wrap(request)));
            buffer.put();
            buffer.flip();
            mysocket.write(buffer);
            return readResponse();
    }

     private String readResponse(SocketChannel mySocket) throws IOException {

    CharsetDecoder myDecoder = Charset.forName("ISO-8859-1").newDecoder();
    ByteBuffer responseHeaderBuf = ByteBuffer.allocate(12);
    responseHeaderBuf.order(ByteOrder.BIG_ENDIAN);
    int bytesRead = 0;
    do {
        bytesRead = mySocket.read(responseHeaderBuf);
    } while (bytesRead != -1 && responseHeaderBuf.position() < 12);

    if (bytesRead == -1) {
        throw new IOException(" : Remote connection closed unexpectedly");
    }

        responseHeaderBuf.flip();
        int lengthField = responseHeaderBuf.getInt();
        int responseLength = lengthField - responseHeaderLength;
        String responseName = myDecoder.decode(responseHeaderBuf).toString();



        ByteBuffer responseBuf = ByteBuffer.allocate(responseLength);
        do {
            bytesRead = mySocket.read(responseBuf);
        } while (bytesRead != -1 && responseBuf.position() < responseLength);

        if (bytesRead == -1) {
            throw new IOException(name + " : Remote connection closed unexpectedly");
        }
        responseBuf.flip();


        if (responseBuf.get(responseBuf.limit() - 1) == END_OF_MESSAGE_BYTE) {
            responseBuf.limit(responseBuf.limit() - 1);
        }
        String response = myDecoder.decode(responseBuf).toString();
        return response;

    }

}

我在客户端无限期地打开SocketChannel

当我在客户端responseHeaderBuf.getInt()中解码响应时,它在第一次运行时是正确的。但是第二次我解码时数据损坏了。

另外,如果使用套接字发送请求,则一切正常,但我想重用我创建的套接字

例如,如果服务器发送了28 processBuffer.putInt(28);个客户端,则说它收到了responseHeaderBuf.getInt()-> 721420288,

能不能帮上忙,告诉我我在做什么错

0 个答案:

没有答案