【问题标题】:BufferedWriter doesn't send text unless stream is closed除非流关闭,否则 BufferedWriter 不会发送文本
【发布时间】:2011-07-25 10:39:33
【问题描述】:

我有一个与客户端通信的服务器。

服务器是多线程的,当从套接字读取的第一行是“请求”时,这个线程是由套接字和连接到套接字的缓冲读取器创建的:

public class scriptComm implements Runnable {

private Socket sock;
private Socket sock2;
private Connection connection;
private BufferedReader reader;

@Override
public void run() {
    try {

        String name = reader.readLine();
        String password = reader.readLine();

        String line;
        connection = methods.connectToDatabase();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
        if (connection != null && name != null && password != null) {
            try {
                ResultSet rs = connection.createStatement().executeQuery(
                        "SELECT name, password, doupdate FROM accounts "
                        + "WHERE name = '" + name + "' AND doupdate = 'yes'"
                        + " AND password = '" + password + "'");
                if (rs.next()) {
                    methods.log("worked");
                    bw.write("accept");
                    bw.flush();
                    bw.close();
                    reader = new BufferedReader(new InputStreamReader(sock2.getInputStream()));
                    if ((line = reader.readLine()) != null) {
                        mainFrame.jTextArea1.append("line \n");
                        connection.createStatement().executeUpdate(
                                "UPDATE accounts SET updatetext = '" + line + "' "
                                + "WHERE name = '" + name + "'");
                    }else{
                        mainFrame.jTextArea1.append("No text received \n");
                    }
                } else {
                    bw.write("decline");
                    bw.flush();
                }
                bw.close();
                rs.close();
            } catch (SQLException ex) {
                methods.log("Error when executing statement in scriptComm");
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        } else {
            methods.log("missing values in scriptComm");

        }
    } catch (IOException ex) {
    }


}

public scriptComm(Socket sock, BufferedReader reader) {
    this.sock = sock;
    this.sock2 = sock;
    this.reader = reader;
}}

您可能会注意到我在写入“accept”后关闭了 bw 流。

这是由于客户端只是挂在那里,就好像它没有收到任何输入一样,当流没有关闭时。

客户:

        try{
        String line;
        Socket sock = new Socket("myipaddresshere",portnumber); 
        PrintWriter writer = new PrintWriter(sock.getOutputStream());
        BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
        writer.println("script");
        writer.flush();
        writer.println(jTextField1.getText());
        writer.flush();
        writer.println(jTextField2.getText());
        writer.flush();
        if ((reader.readLine()).equals("accept")) {
            writer.write("testing123");
            writer.flush();
            writer.close();
        } else {
            jTextArea1.append("fail");

        }
        reader.close();
        writer.close();
    }catch(IOException e){
        jTextArea1.append("Server not available. Please try again later.");
    }

当从服务器写入“accept”后流没有关闭时,就好像客户端只是坐在 if(reader.readLine().equals("accept")) 布尔检查(是的,流在服务器端刷新)。

但是,当流也在服务器端关闭时,它会通过布尔检查并继续将“testing123”行写入流。服务器显然无法读取此行,因为当 BufferedReader 关闭时套接字流已关闭。您可能会注意到,我尝试通过简单地创建另一个名为 sock2 的变量来复制套接字,但似乎这个连接也关闭了(有道理)。

注意:当连接错误的用户/密码时(即当 rs.next() 返回 false 时),它会向流中写入“拒绝”并且客户端会得到这个。

对这个真的很困惑..

谢谢, 迈克。

【问题讨论】:

    标签: java database sockets stream bufferedwriter


    【解决方案1】:

    请注意,写入不会写入换行符,而您正在尝试读取整行。您需要在刷新之前写一个换行符。

    Edither 使用 BufferedWriter.newLine() 或将 "\n" 附加到您编写的字符串中。

    【讨论】:

    • 看起来很傻,我没有发现:p。谢谢。另外:关于从哪里开始阅读有关防止 sql 注入的任何提示?
    • 谷歌就可以了,但是你应该做的是切换到带有参数的PreparedStatement。该 java 类将为您处理转义,因此包含例如的用户名这样双引号或单引号就不再是问题了。
    • 现在使用 PreparedStatement。此外,字符串的长度不得超过 20 个字符,并且不得包含 * 或 = 或短语 select。这应该提供适度的保护,对吧?
    • PreparedStatement 处理 all 转义,因此您现在还可以允许包含 * 或任何看起来像 sql 的用户名。例如,用户名 'select * from blah;drop table foo' 不会有问题。
    【解决方案2】:

    我会留下一条建议:

    当您想将字符写入流时,您应该始终使用具有显式字符编码的OutputStreamWriterInputStreamReader。我推荐“UTF-8”。

    在编写时,您的代码将使用平台默认编码进行读写。这将一直有效,直到您在中国有人在 Windows 上运行客户端,而在美国有人在 Linux 上运行服务器(取决于您发送的内容,它可能会更快中断)。

    【讨论】:

    • 这不是他的问题,问题是他正在使用readLine(),但服务器没有写换行符。
    • @Kaj - 是的,我根据标题回答,然后看到代码中的所有刷新。
    • 我可以再给他一条建议。更改数据库代码,它容易受到 sql 注入攻击 :)
    • 一个很好的建议,谢谢。还将阅读如何防止 sql 注入。关于从哪里开始阅读的任何提示?
    猜你喜欢
    • 2021-10-25
    • 1970-01-01
    • 1970-01-01
    • 2017-07-06
    • 1970-01-01
    • 2014-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多