Java中的IMAP客户端(仅用于套接字)在接收时挂起 [英] IMAP client in Java (sockets only) hangs on receiving

查看:116
本文介绍了Java中的IMAP客户端(仅用于套接字)在接收时挂起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现一个简单的IMAP客户端.我可以连接到服务器,收到它的问候,但是在login命令后接收响应似乎有问题.

I want to implement a simple IMAP client. I can connect to server, receive its greeting but it seems I have a problem receiving the response after the login command.

我知道IMAP行以\r\n.\r\n结尾,但是似乎一次读取一个字节在这里根本行不通,我也不知道为什么.

I know that in IMAP line ends with \r\n or .\r\n but it seems that reading one byte a time simply does not work here and I do not know why.

我的代码:

class NewClass {

    public static String readAll(Socket socket, String end) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        StringBuilder sb = new StringBuilder();
        String line;

        while (!sb.toString().endsWith(end))
        {
            char c = (char)reader.read();
            sb.append(c);
        }
        return sb.toString();
    }

    public static void main(String[] args) throws IOException {
        String host = "x.x.x.x";
        int port = 143;

        Socket socket = new Socket(host, port);

        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);

        // server's greeting
        String initreply = readAll(socket, "\r\n");
        System.out.println(initreply);

        // log me in
        String login_cmd = "A1 LOGIN user pass\r\n";
        writer.print(login_cmd);
        writer.flush();
        String loginreply = readAll(socket, "\r\n");
        System.out.println(loginreply);

    }
}

推荐答案

关于IMAP的内容没有简单,这是从头开始实现的非常复杂的协议.考虑改用预先存在的IMAP库.

There is nothing simply about IMAP, it is a very complex protocol to implement from scratch. Consider finding a pre-existing IMAP library instead.

话虽如此,很显然您没有阅读IMAP规范 RFC 3501 (尤其是第2.2节命令和响应" ),或您会知道您的代码为什么会失败.您的代码不符合规范.

That being said, it is clear that you did not read the IMAP specification, RFC 3501 (in particular, section 2.2 "Commands and Responses"), or you would know why your code is failing. Your code is not compliant with the spec.

尤其是:

  1. 您不会在LOGIN命令的末尾发送尾随的\r\n,因此服务器将不会发送任何响应. PrintWriter.print()不打印换行符. PrintWriter.println()可以,但是它仅打印LF,但是IMAP使用CRLF代替.因此,您需要在发送到服务器的每个命令的末尾添加\r\n.

  1. you are not sending a trailing \r\n at the end of your LOGIN command, so the server will not send any response. PrintWriter.print() does not print a line break. PrintWriter.println() does, but it only prints a LF, but IMAP uses CRLF instead. So you need to include \r\n at the end of every command you send to the server.

您根本无法正确读取服务器响应.您必须阅读行,并考虑*+标记,直到收到以相同的A1标记(与标记LOGIN命令相同)开始的起始行.和.如果使用BufferedReader.readLine()而不是将字符单独读取到StringBuilder中,则该逻辑将更容易实现.从技术上讲,由于IMAP是异步协议,因此您应该以异步方式(例如在后台线程中)进行读取.一次可能有多个命令在运行,并且在命令响应之间服务器可能会发送未经请求的数据.响应中的标签告诉您正在响应哪些命令(如果有).前缀为*的未标记响应应按原样处理,而不管是由哪个命令生成的.

you are not reading the server response correctly at all. You have to read lines, taking the * and + tokens into account, until you receive a line that starts with the same A1 tag that you used to tag the LOGIN command with. The logic would be much easier to implement if you use BufferedReader.readLine() instead of reading characters individually into a StringBuilder. And technically, you should be doing the reading asynchronously, such as in a background thread, as IMAP is an asynchronous protocol. There can be multiple commands in flight at one time, and there can be unsolicited data sent by the server in between command responses. The tags in the responses tell you which commands are being responded to, if any. Untagged responses that are prefixed with the * token should be processed as-is regardless of which command generates them.

这篇关于Java中的IMAP客户端(仅用于套接字)在接收时挂起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆