You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SocketChannel阻塞服务端缓冲区未清空导致重复输出问题求助

问题根源与解决方案

问题出在哪?

你的服务器代码里的reqString是一个全局静态的StringBuffer,每次接收到客户端的字符都会调用reqString.append(c)追加内容,但从来没有清空过它!这就导致每次新接收的字符都会拼在旧内容后面,出现你看到的helloworld、helloworldthis这类拼接结果。

而ByteBuffer的clear()和flip()操作是没问题的——这些只是重置缓冲区的读写位置,和reqString的累加完全是两回事。

修复方案(两种可选)

方案1:每次处理完消息后清空reqString

在打印完消息之后,调用reqString.setLength(0)来清空StringBuffer的内容:

public class EchoServer_1 { 
    private static ByteBuffer buffer = ByteBuffer.allocate(1024); 
    private static StringBuffer reqString = new StringBuffer(); 

    public static void main(String[] args) throws IOException { 
        ServerSocketChannel serverSocketChannel = null; 
        int serverPort = 10007; 
        try{ 
            serverSocketChannel = ServerSocketChannel.open(); 
            serverSocketChannel.socket().bind(new InetSocketAddress (serverPort)); 
            serverSocketChannel.configureBlocking(true); 
            System.out.println("Port number: " + serverPort); 
            System.out.println("Waiting for connection .."); 
            SocketChannel sc = serverSocketChannel.accept(); 
            System.out.println ("Incoming connection from: " + sc.socket().getRemoteSocketAddress( )); 

            while (true) { 
                buffer.clear(); 
                sc.read(buffer); 
                buffer.flip(); 
                while(buffer.hasRemaining()) { 
                    char c = (char) buffer.get(); 
                    if (c == '\r' || c == '\n') break; 
                    reqString.append(c); 
                } 
                log("Message received: " + reqString); 
                // 新增:清空StringBuffer,准备接收下一条消息
                reqString.setLength(0); 
            } 
        }catch (IOException ex) { 
            if (serverSocketChannel != null) serverSocketChannel.close(); 
            System.err.println("Client has disconneted"); 
        } 
    } 

    private static void log(String str) { 
        System.out.println(str); 
    } 
}

方案2:将reqString的声明移到循环内部

这样每次循环都会创建一个新的StringBuffer,自然不会有旧数据残留:

public class EchoServer_1 { 
    private static ByteBuffer buffer = ByteBuffer.allocate(1024); 

    public static void main(String[] args) throws IOException { 
        ServerSocketChannel serverSocketChannel = null; 
        int serverPort = 10007; 
        try{ 
            serverSocketChannel = ServerSocketChannel.open(); 
            serverSocketChannel.socket().bind(new InetSocketAddress (serverPort)); 
            serverSocketChannel.configureBlocking(true); 
            System.out.println("Port number: " + serverPort); 
            System.out.println("Waiting for connection .."); 
            SocketChannel sc = serverSocketChannel.accept(); 
            System.out.println ("Incoming connection from: " + sc.socket().getRemoteSocketAddress( )); 

            while (true) { 
                // 移到这里:每次循环新建一个StringBuffer
                StringBuffer reqString = new StringBuffer(); 
                buffer.clear(); 
                sc.read(buffer); 
                buffer.flip(); 
                while(buffer.hasRemaining()) { 
                    char c = (char) buffer.get(); 
                    if (c == '\r' || c == '\n') break; 
                    reqString.append(c); 
                } 
                log("Message received: " + reqString); 
            } 
        }catch (IOException ex) { 
            if (serverSocketChannel != null) serverSocketChannel.close(); 
            System.err.println("Client has disconneted"); 
        } 
    } 

    private static void log(String str) { 
        System.out.println(str); 
    } 
}

额外说明

客户端的代码逻辑是正确的——每次发送完数据都会调用buffer.clear()重置缓冲区,所以不会出现类似的问题。

修复之后,服务器就能输出预期的单独消息了:

Message received: hello
Message received: world
Message received: this
...

内容的提问来源于stack exchange,提问作者Jose Castano Pardo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:15:32