简体   繁体   English

通过Java套接字接收混合媒体。 你更好吗?

[英]Receiving mixed media over Java socket. Yours better?

I'm about to give a programming exercice in Java and I'd like my students to discover the intrinsics of HTTP themselves rather than having URLConnection doing all the job for them. 我将要用Java编写一个编程练习,我希望我的学生自己发现HTTP的内在特性,而不是让URLConnection为他们完成所有工作。 In order to estimate the complexity, I came up with the following snippet, which parses the reply (imho, one of the hardest part of the job), which will return eg "HTTP/1.1 200 OK" , push things like "Server: makato" and "content-length: 1337" in the headers vector and leave the InputStream at the first byte of the content, so that a DataInputStream or a InputStreamReader can later be built on top of it safely. 为了估算复杂度,我想出了以下代码段,该代码段分析了回复(imho,这是工作中最困难的部分之一),它将返回例如“ HTTP / 1.1 200 OK” ,并推送诸如“ Server: 标头向量中的 makato”“ content-length:1337” ,并将InputStream保留在内容的第一个字节,以便稍后可以在其上安全地构建DataInputStreamInputStreamReader

I'm curious to know if someone with more experience of the Java classes could suggest more elegant alternatives. 我很好奇,如果有人对Java类有更多的经验,可以提出更优雅的替代方法。 One thing I'm not pleased with is that each individual is.read() will inevitably generate an additional system call (assuming that Socket.getInputStream() is used to feed is argument). 有一件事我不是高兴的是,每个人is.read()将不可避免地产生额外的系统调用(假设Socket.getInputStream()被用来饲养参数)。

public static String recvHttpHeaders(InputStream is, Vector<String> headers) 
throws Exception {
byte line[] = new byte[512];
String pending=null;
String status=null;
boolean complete=false, CR=false;
int n=0;

while (!complete) {
    int x = is.read();
    switch(x) {
    case -1: throw new Exception("something went wrong");
    case '\r': 
            if (CR) throw new Exception("encoding mismatch CRCR");
            CR=true;
            break;
    case '\n': // bare LF are accepted silently.
            String ln = new String(line,0,n,"ASCII");
            if (pending!=null) ln = pending + ln;
            if (status==null) status = ln;
            else headers.add(ln);
            complete = ln.length()==0;
            pending = null;
            n=0; CR=false;
            break;
    default:
            if (CR) throw new Exception("encoding mismatch ?CR");
            if (n>=512) {
                String part = new String(line, "ASCII");
                if (pending!=null) pending += part;
                else pending = part;
                n=0;
            }
            line[n++]=(byte)x;
            break;
    }
}
return status;
}

edit : admittedly, one would love to use xxx.readline() here to avoid messing up with lines reconstruction. 编辑 :诚然,有人希望在这里使用xxx.readline()以避免弄乱行的重建。 BufferedReader (or any other *Reader, actually) converts bytes into chars according to one charset. BufferedReader(或其他* Reader实际上)根据一个字符集将字节转换为字符。 That means I'm no longer free to chose that charset for the content if I used that feature in the header parsing. 这意味着,如果我在标头解析中使用了该功能,那么我将不再为该内容选择该字符集。 I haven't found any byte-level classes that has readline ability built-in. 我还没有发现任何内置readline功能的字节级类。

performance solution : Thanks for pointing out BufferedInputStream. 性能解决方案 :感谢您指出BufferedInputStream。 I made a few additional tests, and indeed, invoking as 我做了一些额外的测试,实际上,

   BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
   String status = recvHttpHeaders(bis, headers);
   rawCopy(bis, output);

indeed reduce the amount of system calls performed and still allow me to properly receive binary content unmodified. 确实减少了执行的系统调用的数量,但仍然允许我正确接收未经修改的二进制内容。

根据Sripathi Krishnan和Adam Paynter的评论,对其进行改进的方法是使用BufferedInputStream,这样性能仍然可以接受并且不进行字符集转换。

You should rather use BufferedReader to read texts. 您应该使用BufferedReader读取文本。 Wrap your input stream: 包装您的输入流:

BufferedReder br = new BufferedReader(new InputStreamReader(is));

Then use readLine() to read stuff line by line: 然后使用readLine()逐行读取内容:

String line = null;
while((line = br.readLine()) != null) {
    // deal with the line
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM