【问题标题】:problem with tcp server and clienttcp服务器和客户端的问题
【发布时间】:2011-01-19 11:48:03
【问题描述】:

大家好,我已经创建了一些与客户端和服务器相关的程序。今天是我的客户端-服务器技术会话[实践考试]。

问题是:我要在服务器上添加两个从客户端发送的否,然后将结果返回给客户端。

我尝试了这个解决方案,但出现了一些奇怪的解决方案: 服务器.java

import java.net.*;
import java.io.*;

public class Server{
    public static void main(String args[]) throws Exception{
        ServerSocket s = new ServerSocket(7896);
        Socket cs = s.accept();
        BufferedReader br = new BufferedReader(new InputStreamReader(cs.getInputStream()));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(cs.getOutputStream()));
        bw.write(br.read() + br.read());
    }
}

客户端.java

import java.io.*;
import java.net.*;

public class Client{
public static void main(String args[]) throws Exception{
    Socket s = new Socket("localhost", 7896);
    BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    bw.write(3);
    bw.write(4);
    System.out.println("Output is: " + br.read());
}
}

当我在 dos 提示符下运行它时,我得到了两个空白屏幕;一个在客户端站点,一个在服务器站点(这有点令人惊讶)。然后我关闭了服务器然后突然我在客户端收到错误消息,例如连接关闭。

然后我在我的 ubuntu linux 上使用与 windows 中相同的 jdk 1.6 运行相同的程序,这里也是空白屏幕,但是当我关闭服务器时,我得到了:

Output is: -1

虽然在考试中我使用 DataOutputStream 和 DataInputStream 完成了这项工作。

但是为什么上面的代码不起作用。

任何人都可以解释那里的代码发生了什么。

谢谢

【问题讨论】:

    标签: java networking


    【解决方案1】:

    一些可能会帮助您得出正确答案的 cmets:

    • 服务器代码可以接受 只有一个单个客户端请求,因为 accept() 呼叫不存在 无限循环。
    • 使用缓冲时 流,确保您始终刷新 OuputStream/Writer 确保 数据是实际上写的 对客户而不是只是撒谎 在缓冲区周围。
    • DataInput/OutputStream 是绝对需要的(或任何其他逻辑读取“数字”字符串并将其转换为可以添加的适当表示的方法),因为仅 BufferedReader 读取不要给你“数字”。

    但问题是,为什么需要冲洗?要回答这个问题,首先必须了解为什么要使用“缓冲”。当您可以直接写入您的流时,为什么还要麻烦将您的流包装在另一个流中?原因是 I/O 操作真的很昂贵(至少与访问 RAM 或 CPU 缓存/寄存器相比)。频繁的写入/读取访问/写入小块数据到 HDD 会阻塞您的 HDD 并降低应用程序的整体性能。

    那么解决办法是什么?减少向 HDD 写入数据的频率。有两种方法可以实现:

    1. 手动分配大字节数组 并将整个数组填满 单读。这比 单字节读取。字节数组 尺寸确实需要根据您的调整 应用需求,但对于一般 目的 8K 应该是不错的选择。
    2. 使用缓冲流。这具有不将客户端暴露于低级别细节的优点。您的应用程序可以使用它认为合适的“流”(连续向其写入单个字节),并且流将在它看到时承担刷新 缓冲数据的全部责任适合(这取决于您在创建缓冲流时设置的缓冲区大小)。

    虽然解释是特定于 HDD 的,但同样适用于其他类型的流,例如您的情况下的套接字。

    TL;DR:缓冲提高了 IO 吞吐量/性能。 :)

    【讨论】:

    • Hey sanjay 冲洗后效果很好。但你能告诉我为什么需要冲洗吗?
    • @codeomntrix,因为写入器是缓冲的,缓冲意味着你可以控制何时发送数据。
    • @peter 那么这是否意味着在缓冲区已满之前不会收到它。但是如果我在中间关闭程序怎么办,那么缓冲区中可用的消息会发生什么?如果我关闭流,还会发生同样的事情吗?
    • @codeomnitrix:嗨,我已经用回复更新了我的原始答案。
    • 如果填充缓冲区,flush() 或 close() 写入器,数据将被发送。如果程序终止,任何未发送的数据都将丢失。
    【解决方案2】:

    write() 将缓冲输入,因此它不需要进行大量的小写操作。由于您没有向缓冲区写入太多内容,因此它可能仍然存在并且尚未写出。调用flush() 将强制它写出缓冲区。

    【讨论】:

    • 嘿 unholysampler 感谢您的回复,这是有效的。但是你能告诉我如果我不刷新缓冲区并且输入只是在缓冲区中会发生什么吗?并且由于 tcp 是可靠的选择并且它可以确保交付,那么为什么这是必要的
    • 一旦数据向下传递到传输层,TCP 可确保交付。您的BufferedWriter 位于应用程序层。它正在缓冲您的输入之前将其传递给 TCP。
    • 那么如果我关闭流,它是否会被传递。并且消息实际发生的情况仍保留在缓冲区中。如果我的缓冲区大小为 4 个字节,那么还有一个可行的方法
    • Writer 的文档说close() 调用flush(),但BUfferWriter 只说close() 关闭流。基于此,您似乎需要一本手册 flush(),这对于当程序变得更加复杂并且需要在客户端和服务器之间来回切换时仍然有意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 2012-05-13
    • 2011-08-14
    • 2020-07-15
    • 1970-01-01
    • 1970-01-01
    • 2015-08-29
    相关资源
    最近更新 更多