【问题标题】:HTTPS Socket with request split in chunks请求分成块的 HTTPS 套接字
【发布时间】:2012-10-23 14:44:59
【问题描述】:

我有一个关于 HTTPS 套接字如何工作的问题。

我必须在移动设备和服务器之间实现双向通信。

我从蓝牙设备以原始字节的形式获取请求,但请求是以块的形式接收的,它以相同的方式等待响应。我的意思是:设备正在向我发送一个块,我必须将其发送到服务器,并且我必须将服务器响应发送回设备,以接收第二个块。

这一次有效,我的意思是我正在打开套接字,我正在写入请求块,我正在读取响应块,但是当我写入第二个请求块时,没有从套接字接收到数据.

代码如下:

if (webSocket == null) {
    SocketFactory factory = SSLSocketFactory.getDefault();
    webSocket = factory.createSocket(DataUtils.stringValueFromByteArray(requestPackage.getHostAddress()),
                                                   DataUtils.intValueFromByteArray(requestPackage.getHostPort()));

}
 webInputStream = webSocket.getInputStream();
 webOutputStream = webSocket.getOutputStream();


 webOutputStream.write(requestPackage.getDataContent(), 0,requestPackage.getDataContent().length);
 webOutputStream.flush();

byte[] byteBuffer = getBytesFromInputStream(webInputStream);

getBytesFromInputStream 的样子:

public static byte[] getBytesFromInputStream(InputStream is)
        throws IOException {



    ByteArrayOutputStream bout = new ByteArrayOutputStream();
    byte buf[] = new byte[8192];
    int ret = 0;
    while ((ret = is.read(buf)) != -1) {
        bout.write(buf, 0, ret);
    }

    byte[] bytes = bout.toByteArray();
    return bytes;
}

当请求开始时,webSocket 会得到一个null 值,并且连接不应结束。

现在的问题是这段代码适用于第一个数据块,但在第二个数据块上,getButesFromInputStream 返回一个空数组,因为is.read() 立即返回 -1。

谁能建议我该怎么做,或者向我解释我做错了什么?

任何帮助将不胜感激。 谢谢, 方舟

【问题讨论】:

  • 您可能需要稍等片刻才能让数据有时间送达您。也许你可以用一个while循环和一个小的等待来检测-1
  • 这取决于你的服务器,大概只有你知道它是如何工作的。此外,如果您确实在使用 HTTPS,请不要使用原始套接字,而应使用 HttpsURLConnection 或理解该协议的类似 HTTP 客户端。
  • @njzk2 服务器不是我的,我正在尝试调用任何支持https的页面。
  • @NikolayElenkov 我没有实现服务器,但我请求每个支持 https 的服务器。我将尝试使用 httpsURLConnection 来实现这一点并做出回应。您能否将您的解决方案发布为答案,以便我可以接受它是否有效?谢谢
  • 我已经添加了一个答案,但在尝试之前你可能想问他们预期的协议是什么。

标签: android ssl proxy


【解决方案1】:

如果您确实在使用 HTTPS,请不要使用原始套接字,而应使用 HttpsURLConnection 或理解该协议的类似 HTTP 客户端。然后来自 BT 的每个下一个块将作为一个新请求发送到服务器。

【讨论】:

    【解决方案2】:

    对于 TCP 的一个常见误解是,接收应用程序将在与发送应用程序发送数据的方式相同的块中获取数据片段。 TCP 保证的只是顺序(以及最终交付,前提是没有错误):这应该被视为一个整体的流。

    出于这个原因:

    • 读取 0 字节并不表示套接字已关闭(也是一个常见的误解)
    • 应用协议必须定义分隔符或替代方式来告诉对方何时停止读取,以便能够处理应用协议的各种命令。

    HTTP 1.1 使用Content-Length 标头来告知必须在请求/响应或Chunked Transfer-Encoding 的正文中读取多少字节,而在发送标头时不知道大小。

    如果您想读取 HTTP 请求/响应,您需要处理:标头以空行终止,正文的长度由 Content-Length 或您获得的各种块给出。

    如果您想读取内容长度,则自己实现这一点相对简单,但如果您还希望能够处理分块传输编码,这肯定需要更多的工作。总的来说,您不妨使用 HTTP 库,它会为您完成所有工作。正如 Nikolay 所说,HttpsURLConnection 是一个好方法。如果这不能满足您的需求,您可以使用 Apache Http 客户端库(也随 Android AFAIK 提供)。

    【讨论】:

    • 你可能已经注意到这不是关于 http,而是关于套接字。
    • @njzk2,我有,但问题确实询问了 HTTPS。如果你想在普通套接字上使用你自己的协议,你仍然需要定义你自己的机制该协议中告诉接收者消息从哪里开始和停止。一些协议使用一些长度的标头执行此操作,其他协议使用逐行分隔符(例如 SMTP/POP3 使用. 来结束消息)。你只是需要一些东西。
    • 是,但不是。它询问 https 是因为它询问 websockets,这通常被视为对 http 的升级(字面意思是,因为服务器对握手的回答是“升级:websocket”)。据我了解,升级后的websocket基本上是一个普通的socket
    • @njzk2,不确定它是否是实际的“websocket”(只是看起来的变量名,因为它是客户端代码),但如果是,它确实可以被视为普通套接字,其中如果通过它发送的数据仍然需要被视为流,而不是块。您只能使用某种分隔符来拆分消息,而不是可用多少或每次从缓冲区读取多少。
    • 他使用SSLSocketFactory,所以我猜他使用套接字。 (在这种情况下确实缺少分隔符)
    【解决方案3】:

    getBytesFromInputStream,在你的while之前,添加另一个while:

    while (is.available() == -1) {
        Thread.sleep(100); // for instance. less may very well work too.
    }
    

    这将等待一些数据可供读取。 (数据到达服务器,服务器回复,数据到达你的时间。)

    编辑

    由于某种原因 is.available() 似乎返回 0,您可以使用 is.read 代替:

    while (ret = (is.read(buf)) <= 0) {
        Thread.sleep(100); // for instance. less may very well work too.
    }
    bout.write(buf, 0, ret);
    

    (额外的写入避免丢失实际读取的数据。)

    这个想法是等到从服务器收到一些答案,然后实际读取它。

    【讨论】:

    • is.available() 一直返回 0,所以循环不起作用。
    • 根据缓冲区中剩余的数量停止读取最多只能是巧合(即当它起作用时)。这根本不是处理 TCP 连接的方法。
    • 读取到-1不会读取直到缓冲区中没有任何内容,而是直到接收到流信号结束。
    • 大多数协议在同一个 TCP 连接上交换多个请求/响应:您需要一些东西来告诉对方何时开始和停止,并告诉对方会发生什么。读取 0 或 -1 不是这样做的方法。
    • 你测试了 is.available() 并且它总是返回 0 吗?
    猜你喜欢
    • 1970-01-01
    • 2018-02-24
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多