技术开发 频道

自行开发JSP HTTP服务器的绝对秘籍(二)

【IT168 专稿】

     相关文章:
自行开发JSP HTTP服务器的绝对秘籍(一)
                     自行开发JSP HTTP服务器的绝对秘籍(二)
                     自行开发JSP HTTP服务器的绝对秘籍(三)
                     自行开发JSP HTTP服务器的绝对秘籍(四)
                     自行开发JSP HTTP服务器的绝对秘籍(五)

     第二部分(共5部分)介绍了本JSP HTTP服务器实现的以下特性:
对常规请求(MIME类型文件)的支持
 对CGI(Common Gateway Interface,公共网关接口)的支持

2.对常规请求的支持
这里的常规请求是指请求的资源为文件类型,不需要进行解释,编译,执行等处理。例如:文本文件(*.TXT),超文本文件(*.HTM,*.HTML),脚本文件(*.JS,*.VBS等),图片文件(*.JPG,*.PNG,*.GIF,*.BMP)。

处理基于文件流的请求较为简单。只需要读取本地的文件资源,再发送给客户端即可。

2.1 文件流请求的处理示例代码

//Create client socket output stream m_sout = new PrintWriter(m_s.getOutputStream(), true); m_soutx = null; m_sout.println("HTTP/1.0 200 OK\nMIME-Version:1.0\nContent-Type:text/html\n\n"); File file = new File(fileName); if(file.exists() == true) { //Create local file input stream BufferedReader fin = new BufferedReader(new FileReader(file) ); String line = null; String response = ""; //Read file by lines while( (line = fin.readLine() ) != null) { response = response + line + "\n"; } //Send the content to client socket m_sout.println(response); //Close local file handle fin.close(); }

以上是处理基于文本流的请求,以下是处理基于二进制流的请求实例代码。

2.2 二进制流文件的处理示例代码

//Create client socket output stream m_soutx = m_s.getOutputStream(); m_sout = null; String header = "HTTP/1.0 200 OK\nMIME-Version:1.0\n"; //Send content to client socket m_soutx.write(header.getBytes() ); String mime = ""; //Get MIME by file type switch(typeFlag) { case TYPE_JPEG: //jpeg file { mime = "image/jpeg"; break; } case TYPE_GIF: //gif file { mime = "image/gif"; break; } case TYPE_BMP: //bmp file { mime = "image/bmp"; break; } case TYPE_PNG: //png file { mime = "image/png"; break; } } mime = "Content-Type:" + mime + "\n\n"; m_soutx.write(mime.getBytes() ); File file = new File(fileName); if(file.exists() == true) //Read image files and send to client socket { //Create local file input stream RandomAccessFile fin = new RandomAccessFile(fileName, "r"); final long size = fin.length(); byte [] buffer = new byte[(int)size]; fin.readFully(buffer); fin.close(); //Send data to client socket m_soutx.write(buffer); } //Close client socket output stream m_soutx.close();

从以上代码可以看出,处理文本流和二进制流的请求的方式是不相同的,文本流的文件是按照行进行处理,而二进制流的文件是以批量读取。

其中关键的是,对于不同的文件类型,发送数据给客户端时必须指明服务器端应答的媒体类型,即MIME(Multipurpose Internet Mail Extensions),这样应答给客户端的资源才能被客户端浏览器所识别,并调用相应的应用程序对资源进行读取。下表2是部分常用类型文件和其对应的MIME。
文件类型 扩展名 MIME
文本文件 .TXT text/plain
HTML(HyperText Markup Language)文件 .HTML,.HTM text/html
JPEG(Joint Photographic Experts Group)文件 .JPG,.JPEG image/jpeg
PNG(Portable Network Graphic Format)文件 .PNG image/png
BMP(Bitmap)文件 .BMP application/x-MS-bmp
GIF(Graphics Interchange Format)文件 .GIF image/gif
XML(EXtensible Markup Language)文件 .XML text/xml
表2:常用类型文件的MIME

3.对CGI的支持

支持CGI简而言之就是支持客户端调用服务器端的CGI例程。在服务器端,CGI一般以可执行文件的形式存放(例如:可执行文件,可执行脚本)。这些CGI执行文件可以单独运行也可以接受客户端的请求作为参数运行。而HTTP服务器就要担负起调用CGI可执行文件以及将客户端的请求参数传递给CGI程序,并将CGI的执行结果反馈给客户端。

3.1 不需要参数的CGI程序的调用

对于不需要参数的CGI程序,已经将功能模块固定设置到CGI程序中,当调用时,执行该功能模块即可。这种类型的CGI程序一般用于功能比较固定的场合。以下是既支持需要参数的CGI也支持无需参数的CGI的代码:

//Parameter is null if(params.equals("") == true) { command = fileName; } else //Generate the command line { command = fileName + " " + params; } //Execute CGI process as child process Process proc = m_rt.exec(command, null); //Create CGI process output stream BufferedReader pin = new BufferedReader(new InputStreamReader(proc.getInputStream() ) ); String line = null; //Get the output from CGI process while( (line = pin.readLine() ) != null) { m_sout.println(line); } //Wait for CGI process finish proc.waitFor();

以上代码中,通过Java的Runtime类的exec接口调用CGI可执行文件,并将CGI的执行输出返回给客户端。

3.2 需要参数的CGI程序的调用

对于需要参数的CGI程序,功能模块没有固定,而是需要以及传入参数才能执行相应的功能。这种类型的CGI程序相对比较灵活。被调用时,HTTP服务器必须将客户端请求中的参数行传入到CGI进程中,在CGI程序中对请求进行解析,进而执行相应的模块。HTTP服务器与CGI进程的通信可以采用三种方式:

(1)以命令行的方式传入执行参数。参见以上代码(“command = fileName + " " + params;”)中。将可执行文件和参数作为命令行传入调用。
(2)写入到CGI进程的标准输入(stdin)中,CGI程序只需要从标准输入中读取相应的参数行即可。
(3)将参数行写入到CGI进程的环境变量QUERY_STRING中。CGI从环境变量QUERY_STRING中读取命令行参数。
本设计中,使用的是方式(1)。

0
相关文章