1、概论
HTTP系统包括客户端软件(浏览器)和服务器软件(HTTP服务器)。早期的客户端软件,其主要工作可理解为文件下载和文件显示。
实际上现代的HTTP客户端比文件下载要复杂得多,它包括网页文件的下载、跨平台的本地显示,参数的传递,动态网页的实现,以及交互等功能。
HTTP系统程序设计包括:
(1) 客户端软件(web浏览器软件如IE浏览器、360浏览器)
(2) 服务器软件(web服务器软件如微软的IIS,Apache Tomcat等)。
HTTP系统客户端的工作过程是:
(1) 客户端软件和服务器建立连接(TCP的三次握手);
(2) 发送HTTP头格式协议;
(3) 接收网页文件;
(4) 显示网页。
HTTP系统服务端的工作过程:
(1) 服务器软件开启80端口;
(2) 响应客户的要求、完成TCP连接;
(3) 检查客户端的HTTP头格式发送客户请求的网页文件(含动态网页)。
本课题主要学习网页下载程序设计技术。网页下载技术是搜索引擎、网络爬虫、网页采集器或网络推送服务等相关应用领域内的基础技术。
2、程序设计第一步:基于TCP套接字Socket的网页下载程序设计
利用TCP客户套接字Socket(host,port)和HTTP服务器进行信息交互,具体工作如下:
(1)新建一个包名:http,新建或将原有的TCPClient.java程序复制并重新命名为HTTPClient.java,其中字符输出流的编码设定为“ASCII”或者“GB2312”,字符输入流的汉字编码一般设定为“UTF-8”。
图1 TTTP连接窗口
(2)创建HTTPClientJFrame.java程序,界面设计如图1。在“连接”按钮中放置连接服务器的代码和启动输入流“读线程”。
在“网页请求”按钮中发送HTTP请求头标准格式(关于HTTP请求头的更多信息可查阅互联网)。
HTTP的头格式如下(具体见例子程序):
// GET /index.jsp HTTP/1.1;//访问指定网页.
GET / HTTP/1.1;//访问默认网页,注意‘/’前后要留有空格
Host: "+address+";//address指服务器的IP或域名
Accept: */*;
Accept-Language: zh-cn;
Accept-Encoding: gzip, deflate;
User-Agent: Mozilla/4.0(compatible; MSIE 6.0; Windows XP);
Connection: Keep-Alive;
将上述的HTTP头格式构成一个字符串(通常用StringBuffer类),一致发送到HTTP服务器。
具体如下
String ip = jTextField1.getText();
StringBuffer msg = new StringBuffer("GET / HTTP/1.1" + "\r\n"); //
// StringBuffer msg = new StringBuffer("GET / connecttest.txt HTTP/1.1 " + "\r\n"); //注意/后面需要有空格
msg.append("HOST:" + ip + "\r\n");
msg.append("Accept: */*" + "\r\n");
msg.append("Accept-Language: zh-cn" + "\r\n");
msg.append("Accept-Encoding: deflate" + "\r\n");
msg.append("User-Agent:Mozilla/4.0(compatible;MSIE6.0;Windows XP)" + "\r\n");
msg.append("Connection:Keep-Alive" + "\r\n");
//msg.append
tc.send(msg.toString());
3、程序设计第二步:基于URL类的网页下载程序设计
(1)利用URL类来访问HTTP服务器,主程序为URLClientJFrame.java。,界面布局可参见如图2所示。
图2 使用URL类实现HTTP访问
在“发送”按钮中设置如下关键代码,并安置和启动一个输入流“读线程”。
//创建URL实例(完成3次握手连接,并自动选择不同的头格式),其中IPAddress是字符串类型,形如:http://www...或ftp://。
URL url = new URL(IPAddress);
//取得URL的字节输入流
InputStream in=url.openStream();
//装饰成字符输入流
BufferedReader br;
br=new BufferedReader(new InputStreamReader(in,"utf-8"));
(3) 在输入框中实现鼠标拖动URL地址自动获取功能,如图3所示.
图3 鼠标自动获取URL地址
4、程序设计进阶之一:使用文本窗格类显示网页文件的程序设计
上述程序设计仅仅实现了网页文件的下载,若想要一定的网页显示功能,则可利用面板组件中的“文本窗格”类来访问服务器,其主程序为WebClientJFrame.java。
从组件面板中选择“文本窗格”,安置到相应位置,去掉可编辑属性,界面布局如图4所示。
图4 一个简单的浏览器
在“发送”按钮中设置如下代码:
IPaddress=jTextField1.getText();
try {
//完成TCP连接、网页下载并呈现。
jTextPane1.setPage(IPaddress);
} catch (IOException ex) { }
若想窗口程序响应鼠标超链接动作,则在WebClientJFrame类定义中继承超级链接响应的接口:implements HyperlinkListener。
在构造方法中添加超级链接监听方法,如鼠标移动、点击等,如:
jTextPane1.addHyperlinkListener(this);
在主程序中实现抽象方法hyperlinkUpdate(HyperlinkEvent evt),响应鼠标动作
还可以做成一个小小的浏览器程序:
页面显示:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String IPAddress = jTextField1.getText();
// URL url=new URL(jTextField1.getText());
try
{
URL url=new URL(jTextField1.getText());
// jTextPane1.setPage(IPAddress);
jTextPane1.setPage(url);
}catch(Exception e)
{
e.printStackTrace();
}
}
点超链接:
private void jTextPane1MouseClicked(java.awt.event.MouseEvent evt) {
jTextPane1.addHyperlinkListener(this);// TODO add your handling code here:
}
private void jTextPane1MouseMoved(java.awt.event.MouseEvent evt) {
jTextPane1.addHyperlinkListener(this);// TODO add your handling code here:
}
超链接:
@Override
public void hyperlinkUpdate(HyperlinkEvent evt) {
// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
try
{
if(evt.getClass() == FormSubmitEvent.class) //处理表单提交事件
{
FormSubmitEvent fevt = (FormSubmitEvent)evt;
URL url = fevt.getURL();//获得URL
String method = fevt.getMethod().toString();//获得请求方式
String data = fevt.getData();//获得表单数据
if(method.equals("GET"))//如果为Get方法
{
jTextPane1.setPage(url.toString()+"?" + data);
jTextPane1.setText(url.toString() + "?" + data);
//把文本框设为用户选择的超级链接
}else
{
if(method.equals("POST"))//如果为POST方法
{
URLConnection uc = url.openConnection();
//发送HTTP响应正文
uc.setDoOutput(true);
OutputStreamWriter out = new OutputStreamWriter(uc.getOutputStream());
out.write(data);
out.close();
//接收HTTP响应报文
InputStream in = uc.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len = -1;
while((len =in.read(buff))!=-1)
{
buffer.write(buff,0,len);
}
in.close();
jTextPane1.setText(new String(buffer.toByteArray()));
jTextField1.setText(url.toString()); //J将文本框设为用户选择的超级链接
}
System.out.println(fevt.getData() + "|" + fevt.getMethod() + "|" + fevt.getURL());
}
}else
if(evt.getEventType()== HyperlinkEvent.EventType.ACTIVATED)
{//处理用户选择的超级链接
jTextPane1.setPage(evt.getURL());
jTextField1.setText(evt.getURL().toString());
}
}catch(Exception e1)
{
jTextPane1.setText(evt.getURL().toString());
e1.printStackTrace();
}
}