网络编程的定义:
网络编程从大的方面说就是对信息的发送到接收,中间传输为物理线路的作用,编程人员可以不用考虑;网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的。中间最主要的就是数据包的组装,数据包的过滤,数据包的捕获,数据包的分析,当然最后再做一些处理。TCP/IP是目前网络应用程序的首选协议。编写基于基于TCP/IP协议的网络程序,必须先了解两个重要的概念:IP地址和Port(端口号)。
IP地址占用4个字节,Port是一个占用两个字节的整数(范围在0~65535之间,0~1023之间的端口数是用于一些知名的网络服务和应用)。本地回路IP地址是127.0.0.1。
关于TCP和UDP协议的较详细介绍:
TCP(Transmission Control Protocol ):是面向连接的通信协议。在正式通信之前必须先与对方建立连接。可靠性较好,其工作过程类似于打电话。过程大致如下:
1.建立连接,形成传输数据的通道。
2.在连接中进行大量的数据传输。
3.通过三次握手完成连接,是可靠协议。因为必须建立连接所有工作效率可能会稍低。
4.其实很多应用程序协议都是基于TCP网络通信协议的,比如HTTP协议,FTP协议,STMP协议,POP3协议等。
UDP(User Datagram Protocol):是无连接的通信协议。在正式通信之前不必与对方先建立连接,直接通过数据报传输数据。可靠性较差。其工作过程类似于电台发送广播。过程大致如下:
1.将数据源和目的封装成数据包,不需要建立连接。
2.每个数据的大小限制在64k内
3.因无连接,是不可靠协议。
4.因不需要建立连接,速度较快。
在网络上一台主机个另外一台主机通讯的大致过程:
1.找到对方的ip
2.数据发送到对方指定的应用程序上,为了标识这些应用程序,所以给出这些网络应用程序都用数字进行标识。为了方便称呼这个数字。我们把这个数字称为端口或逻辑端口
3.定义通信规则。这个通讯规则称为协议。国际组织定义了通过协议TCP/IP。
总结起来网络通讯的要素为:
1.IP地址:网络设备的标示,不易记忆,但可以用主机名代替。本地回环地址:127.0.0.1 主机名:localhost。
2.端口号 :用于标识进程的逻辑地址,不同进程的标识。有效端口:0~65535,其中0~1024系统使用或是保留的端口。
3.传输协议:即通信规则,常见的协议有:TCP和UDP。
例子:利用QQ或FeiQ在网络上与其他人进行交流:
网络模型:
1.OSI(Open System Interconnection)参考模型
2.TCP/IP参考模型
模型图如下:
Socket编程:
网络编程可以说就是指Socket编程。Socket是网络驱动层提供给应用程序编程的接口和一种机制。
Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和Port。
通信的两端都有Socket。网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。
以下利用Socket编程去写分别个关于UDP和TCP传输的小程序去大概了解Socket编程的过程。
1 UDP通信:
在UDP通信中主要使用到的两个类有:DatagramSocket类和DatagaramPacket类。若把DatagramSocket比作创建的港口码头,那么DatagramPacket就是发送和接收数据的集装箱。
DatagaramSocket的基本用法:
主要是用于创建接收和发送UDP的Socket实例。常用的方法有:
DatagramSocket()//构造方法:构造数据报套接字并将其绑定到本地主机上任何可用的端口;提示:如果UDP程序不用事先接收对方发送的数据,而是主动先给对方发送数据,那最好就用这个构造函数来创建对象。
DatagramSocket(int port)//构造方法:创建数据报套接字并将其绑定到本地主机上的指定端口;提示:如果UDP程序有可能先接收别人发送的数据,那就必须得用这个构造函数来创建对象。
DatagramSocket(int port, InetAddress laddr)//创建数据报套接字,将其绑定到指定的本地地址;提示:如果UDP程序要在有多个IP地址的计算机上运行,那么就得用这个构造函数来创建对象。
public void close()//关闭此数据报套接字并通知驱动程序释放与此对象所关联的资源。
public void send(DatagramPacket p)//从此套接字发送UDP数据报包。
public void receive(DatagramPacket p)//从此套接字接收UDP数据报包。
DatagaramPacket的基本用法:
用于存放数据的数据包。常用的方法有:
DatagramPacket(byte[] buf, int length)//构造函数: 构造 <code>DatagramPacket</code>,用来接收长度为 <code>length</code> 的数据包。
DatagramPacket(byte[] buf, int length, InetAddress address, int port)//构造函数: 构造数据报包,用来将长度为 length的包发送到指定主机上的指定端口号。InetAddress此类表示互联网协议 (IP) 地址,在这里表示数据送往的目的地址
public InetAddress getAddress()//返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
public int getPort()//返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。
public byte[] getData()返回数据缓冲区。
public int getLength()返回将要发送或接收到的数据的长度。
例子程序:
需求:通过udp传输方式,将一段文字发送出去。
思路:定义一个udp的发送端
1)建立udpsocket服务
2)提供数据,并将数据封装到数据包中
3)通过Socket服务的发送功能,将数据包发送出去
4)关闭资源
代码:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPSend {
public static void main(String args[])throws Exception{
//创建UDP服务,通过DatagramSocket对象
DatagramSocket ds=new DatagramSocket();
//确定数据,并封装成数据包
byte[] buf="UDP I am coming".getBytes();
DatagramPacket dp=new DatagramPacket(buf, buf.length,InetAddress.getByName("192.168.1.254"), 10000);
//通过Socket服务,将已有的数据包发送出去,通过send的方法
ds.send(dp);
//关闭资源
ds.close();
}
}
需求:定义一个应用程序,用于接受并处理数据
思路:
1)定义UDPSocket服务。通常会监听一个端口。其实是给这个接受网络应用程序定义数字标识。方便于明确哪些数据过来该应用程序可以处理。
2)定义一个数据包,因为要存储接受收到的字节数据,因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
3)通过socket服务的recieve方法将收到的数据存入已定义好的数据包中。
4)通过数据包对象特有的功能,将这些不同的数据取出。打印在控制台上。
5)关闭资源。
代码:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPRece {
public static void main(String args[]) throws Exception{
DatagramSocket ds=new DatagramSocket(1000);
//1创建udp socket,建立端点,DatagramSocket ds=new DatagramSocket(1000);此服务不要循环建立
while(true){
//2定义数据包,用于存储数据
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
//3.通过服务的recive方法将收到数据存入数据包中
ds.receive(dp);
//4.通过数据包的方法获取其中的数据
String ip=dp.getAddress().getHostAddress();
String data=new String(dp.getData(),0,dp.getLength());
int port=dp.getPort();
System.out.println(ip+"::"+data+"::"+port);
//5.关闭资源
ds.close();
}
}
}
编写一个UDP的简易聊天小程序:程序要注意的地方:有接受数据的部分,和发送数据的部分。这两部分需要同时执行。那就需要用到多线程技术。一个线程控制收,一个线程控制发。
因为收和发的动作不一致的,所以要定义两个run方法。而且这两个方法要封装到不同的方法中。
代码:
1)接收:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Rece implements Runnable{
private DatagramSocket ds;
public Rece(DatagramSocket ds){
this.ds=ds;
}
@Override
public void run() {
// TODO Auto-generated method stub
try{
while(true){
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
ds.receive(dp);
String ip=dp.getAddress().getHostAddress();
String data=new String(dp.getData(),0,dp.getLength());
System.out.println(ip+"::"+data);
}
}catch(Exception e){
throw new RuntimeException("接收端异常");
}
}
}
2)发送:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Send implements Runnable{
private DatagramSocket ds;
public Send(DatagramSocket ds){
this.ds=ds;
}
public void run(){
try{
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
String line=null;
while((line=bufr.readLine())!=null){
if("886".equals(line))
break;
byte[] buf=line.getBytes();
DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.255"),10002);
ds.send(dp);
}
}catch(Exception e){
throw new RuntimeException("发送端发送失败");
}
}
}
3.启动程序
import java.net.DatagramSocket;
public class chatDemo {
public static void main(String args[]) throws Exception{
DatagramSocket sendSocket=new DatagramSocket();
DatagramSocket receSocket=new DatagramSocket(10002);
new Thread(new Send(sendSocket)).start();
new Thread(new Rece(receSocket)).start();
}
}
1 TCP通信:演示TCP传输
1)tcp分客户端和服务端
2)tcp中主要用到两各类,ServerSocket类和Socket类;其中ServerSocket类主要用于TCP通信的服务器,Socket类用于TCP通信的服务器和客户端。
ServerSocket类的基本用法:ServerSocket用于绑定端点,提供服务,并接受连接请求,如果写服务器一定要用到的。ServerSocket类的常用方法如下:
ServerSocket()//创建非绑定服务器套接字。
ServerSocket(int port)//创建绑定到特定端口的服务器套接字。
public Socket accept()//侦听并接受到此套接字的连接。
public void close()//关闭此套接字。
public int getLocalPort()//返回此套接字在其上侦听的端口。</span></span>
Socket类的基本用法:Socket就是普通的连接套接字,做客户端要用到,设计服务器的时候也要用到。服务套接字accept之后返回的是Socket对象,所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。Socket类常用的方法如下:
Socket()//通过系统默认类型的 SocketImpl 创建未连接套接字
Socket(InetAddress address,int port)//创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
public void connect(SockectAddress endpoint)//将此套接字连接到服务器。
public InetAddress getInetAddress()//返回套接字连接的地址。
public InputStream getInputStream()//返回此套接字的输入流。
public OutputStream getOutputStream()//返回此套接字的输出流。
public int getPort()//返回此套接字连接到的远程端口。
public void shutDownInput()//此套接字的输入流置于“流的末尾”。
public void shutDownOutput()//禁用此套接字的输出流。</span></span>
3.客户端对应的对象是socket,服务端对应的对象是serverSocket
客户端: 通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机。 因为tcp是面向连接的。所以在建立服务时,就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输
4.TCP客户端程序与TCP服务器端程序的交互过程:
(1)服务器程序创建一个ServerSocket,然后调用accept()方法等待客户端来连接;
(2)客户端程序创建一个Socket并请求与服务器建立连接;
(3)服务器接收客户端的连接请求,并创建一个新的Socket与该客户端建立专线连接;
(4)建立了连接的两个Socket在一个单独的线程(由服务器程序创建)上对话;
(5)服务器开始等待新的连接请求,当新的连接请求到达时,重复步骤2到步骤5的过程。
提示:当我们为需要指定端口的对象指定端口的时候一定要注意不能使用已经被别的程序占用了的端口,否则程序将不能正常的运行。
需求:给服务端发给一个文本数据。
步骤:
1.创建socket服务,并指定要连接的主机端口。
代码:
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class TCPClient {
public static void main(String args[]) throws Exception, IOException{
//创建客户端的socket服务。指定目的主机端口
Socket s=new Socket("192.168.1.254",10003);
//为了发送数据,应获取socket流中的输出流
OutputStream out=s.getOutputStream();
out.write("TCP your i am coming".getBytes());
s.close();
}
}
服务端:定义端点接受数据并打印在控制台上。
步骤:
1.建立服务端的socket服务。ServerSocket();并监听一个端口。
2.获取连接过来的客端对象,通过ServerSocket的accept方法。没有连接就会等待,所以这个方法是阻塞式的
3.客户端如果发过来数据,那么服务端要使用对应的客户端对象并获取到该客户端对象的读取流来读取发过来的数据。
4.关闭服务端(可选的操作)
代码:
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String args[]) throws Exception{
//建立服务端Socket服务。并监听一个端口
ServerSocket ss=new ServerSocket(10003);
//通过accept方法获取连接过来的客户端对象
Socket s=ss.accept();
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+"......connected");
//获取客户端发送过来的数据,那么要使用客户端的读取流来读取数据
InputStream is=s.getInputStream();
byte[] buf=new byte[1024];
int len=is.read(buf);
System.out.println(new String(buf,0,len));
s.close();//关闭服务端以免浪费服务端资源
ss.close();
}
}
演示TCP文件上传:需求:将本地的一个文本文件上传到服务端
代码:
客户端:
package com.upload;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class TextClient {
public void main(String args[]) throws Exception, IOException {
Socket s = new Socket("192.168.254", 10006);
BufferedReader bufr = new BufferedReader(new FileReader("IPDemo.java"));
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
String line = null;
while ((line = bufr.readLine()) != null) {//这里的readline方法并没有将结束符读出并发送出去
out.println(line);
}
s.shutdownOutput();//关闭客户端的输出流,相当于给流中加入一个结束标记-1
BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
String str=bufIn.readLine();
System.out.println(str);
s.close();
}
}
服务端:
package com.upload;
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TextServer {
public static void main(String args[]) throws Exception {
ServerSocket ss=new ServerSocket(10006);
Socket s=ss.accept();
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+"...connected");
BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter out=new PrintWriter(new FileWriter("server.txt"));
String line=null;
while((line=bufIn.readLine())!=null){
out.println(line);
}
PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
pw.println("上传成功");
out.close();
s.close();
}
}
网络资源访问:
访问internet网络资源主要的类有java.net包中的URL,URLDecoder,URLEncoder,URLConnection,HttoURLConnection等类。
URI(Uniform Resource Identifier)表示统一资源标识符。
URL(Uniform Resource Locator)表示统一资源定位符,用于表示internet网络资源的地址。网络资源可以是一个文件,一个目录,或者是一个复杂的对象。
URL的基本组成:协议、主机名、端口号、资源名。
如:http://www.kid.com:8080/index.html 提示:若服务器监听的是80端口就不要在主机明后加上端口号了。因为HTTP协议的默认端口号就是80,如果某种协议的服务器程序使用的监听端口号是默认端口号,那么在连接网络服务器的时候URL中就可以不指定端口号,客户端程序就会使用协议的默认端口号去连接网络服务器。
在Java中,URI类不包含用于访问通用资源标识符设定的任何方法,它的唯一作用是进行分析。相反,URL类则可以打开到达资源的一个字符串。
URL中的端口号部分用来指定客户端程序要连接的网络服务器程序的监听端口号,每一种标准的网络协议都有一个默认的端口号,一个完整的URL可以由一个基准URL和一个相对URL组合而成。
基准URL就是当前网页所在的目录路径;
相对URL的表示:
/a.html-------以/开头表示主机上的某种协议的根目录。
../a.html-------以../开头表示当前资源所在目录的父目录。
a.html或者./a.html-------直接使用文件名、目录名或者以./开头则表示当前资源目录下的文件或者子目录。
浏览器访问3W服务器上的网页文件时,需要使用HTTP协议进行通信,在HTTP协议中,浏览器不能向服务器直接传送某些特殊的字符,必须对这些字符进行URL编码后再传送。
提示:在html中通过表单提交的数据(post和get都可以)数据时浏览器会智能的进行URL编码,但在其他情况下若不进行URLEncoder.encode()进行编码服务器会识别不了中文等其他字符,只能识别英文。
URL编码规则:
将空格转换为加号(+);对0~9,a~z,A~Z之间的字符保持不变;
对于所有其他的字符,用这个字符的当前字符集编码在内存中的十六进制格式表示,并在每个字节前加上一个百分号(%)。如:字符“+”用%2B表示,字符“=”用%3D表示,
字符“&”用%26表示,每个中文字符在内存中占两个字节,字符“中”用%D6%D0表示,字符“国”用%B9%FA表示。
对于空格也可以直接使用其十六进制的编码方式,而不是将它转换成加号(+)。
java.net包中提供了URLEncoder和URLDecoder这两个类,来实现URL编码和解码。
HTTP协议:
HTTP消息分为请求消息和响应消息。
HTTP协议定义了web浏览器和web服务器之间交换数据的会话过程以及数据本身的格式。
可以简单的认为HTTP协议规定了浏览器从3W服务器上获取网页文件的方式。
HTTP请求消息:一个完整的请求消息包括:一个请求行、若干个消息头、以及实体内容。
例如:
Accept-Encoding: gzip, deflate
GET /img/bd_logo1.png HTTP/1.1
Accept: image/png, image/svg+xml, image/*;q=0.8, */*;q=0.5
X-HttpWatch-RID: 7881-10008
Referer: http://www.baidu.com/?tn=10018801_hao
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: www.baidu.com
If-Modified-Since: Wed, 03 Sep 2014 10:00:27 GMT
If-None-Match: "1ec5-502264e2ae4c0"
DNT: 1
Connection: Keep-Alive
Cookie: BD_UPN=11263143; BD_HOME=0; BDSVRTM=0; BAIDUID=
提示:请求消息中的第一行就是请求行,后面紧跟的内容(直到一个空行跟实体内容分隔)都属于消息头部分,消息头和实体内容是可选的,消息头和实体内容要用空行隔开
HTTP响应消息:一个完整的响应消息包括:一个状态行、若干个消息头、以及实体内容。
例如:
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Thu, 13 Jul 2000 05:50:53 GMT
Content-Length: 2291
Content-Type: text/html
Set-Cookie: ASPSESSIONIDQQGGGNCG=LKLDFFKCINFLDMFHCBCBMFLJ;path=/
Cache-control: private
<html>
<head>
......
提示:响应消息中的第一行就是状态行,后面紧跟的内容(直到一个空行跟实体内容分隔)都属于消息头部分,消息头和实体内容也是可选的,消息头和实体内容要用空行隔开
HTTP消息中的消息头是用来描述这个HTTP消息中的一些特性,这种用来描述信息的信息被称为元信息。
了解几个HTTP消息头:
Connection: 用于指定处理完本次请求/响应后,客户端与服务器是否继续保持连接,设置值可以为Keep-Alive和close。默认是Keep-Alive。
Accept-Language: 用于指定客户机期望服务器返回的文档所使用的国家语言,可以指定多个以逗号分隔的国家语言。
Content-Length: 用于表示实体内容的长度(字节数)。
Range: (请求消息头)用于指定服务器只需返回文档中的部分内容及内容范围,有以下几种使用格式。
(1)Range: bytes=100-599 表示只返回从第100个字节到第599个字节之间的内容,包括第100个字节和第599个字节,字节的顺序是从0开始计算。
(2)Range: bytes=100- 表示请求服务器只返回第100个字节以后的全部内容。
(3)Range: bytes=-100 表示请求服务器只返回最后100个字节的内容。
这个头字段,对于较大文档的断点续传非常有用,如果客户端在一次的请求中只接收到了服务器返回的部分内容就中断了,那么它可以在第二次的请求中使用Range头字段要求服务器只返回从上次中断位置以后的内容。这样就节省了网络下载的时间。
Content-Range: (响应消息头)用于指定服务器返回的部分实体内容的位置信息,例如:Content-Range: bytes 2543-4532/7898(起始位置-终止位置/整个实体内容的大小)。
一个使用GET方式的请求消息中不能包含实体内容,只有使用POST等方式的请求消息中才可以包含实体内容。
如果一个HTTP消息中包含了实体内容,那么在它的消息头部分必须要有Content-Length这个字段,用来告诉接收方实体内容的长度。
使用telnet来访问网络资源,体会HTTP协议的会话过程:
1 使用 telnet www.it315.org 80 连接上web服务器
2 然后输入 GET /index.html HTTP/1.1
Host:
3 然后我们可以继续访问此服务器上的资源,如:
GET /images/logo.gif HTTP/1.1
Host:
Connection: close ------表示访问完后断开连接。
工厂设计模式(XxxFactory-----getXxx())
一个查看的例子:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class GetWeb {
public static void getContent(String urlString, String language)
throws Exception {
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Accept-Language", language);
Map<String, List<String>> requests = connection.getRequestProperties();
Set<String> reqFields = requests.keySet();
for (Iterator itereq = reqFields.iterator(); itereq.hasNext();) {
String field = (String) itereq.next();
System.out.println(field + ":"
+ connection.getRequestProperty(field));
}
System.out.println("-------------------------------------");
/*
* 这个方法我们可以不调用,因为我们下面调用了getXxxxx()方法 的时候就会自动跟服务器建立连接。
*/
// connection.connect();
Map<String, List<String>> responses = connection.getHeaderFields();
Set<String> resFields = responses.keySet();
for (Iterator iteres = resFields.iterator(); iteres.hasNext();) {
String field = (String) iteres.next();
System.out.println(field + ":" + connection.getHeaderField(field));
}
BufferedReader bfr = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String strLine = null;
while ((strLine = bfr.readLine()) != null) {
System.out.println(strLine);
}
bfr.close();
connection.disconnect();
}
public static void main(String[] args) throws Exception {
getContent("http://www.baidu.com", "zh-HK");
}
}
打印结果为:
Accept-Language:zh-HK
-------------------------------------
null:HTTP/1.1 200 OK
Expires:Fri, 24 Oct 2014 03:20:20 GMT
Set-Cookie:H_PS_PSSID=9180_8661_9008_1467_7801_9143_9498_6506_9509_6018_8593_7825_7799_9453_7963_9193_8973_9023_9188; path=/; domain=.baidu.com
Connection:Keep-Alive
Server:BWS/1.1
X-Powered-By:HPHP
Cache-Control:private
Date:Fri, 24 Oct 2014 03:21:03 GMT
Transfer-Encoding:chunked
BDQID:0x89afc89a00018c18
Vary:Accept-Encoding
P3P:CP=" OTI DSP COR IVA OUR IND COM "
BDPAGETYPE:1
Cxy_all:baidu+8be5a3db2ca6c52b41a908b4f21f05b6
BDUSERID:0
Content-Type:text/html; charset=utf-8
<!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="content-type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=Edge"><link rel="dns-prefetch" href="//s1.bdstatic.com"/><link rel="dns-prefetch" href="//t1.baidu.com"/><link rel="dns-prefetch" href="//t2.baidu.com"/><link rel="dns-prefetch" href="//t3.baidu.com"/><link rel="dns-prefetch" href="//t10.baidu.com"/><link rel="dns-prefetch" href="//t11.baidu.com"/><link rel="dns-prefetch" href="//t12.baidu.com"/><link rel="dns-prefetch" href="//b1.bdstatic.com"/><title>鐧惧害涓?笅锛屼綘灏辩煡閬?/title>
<style index="index" id="css_index">html,body{height:100%}html{overflow-y:auto}#wrapper{position:relative;_position:;min-height:100%}#head{padding-bottom:100px;text-align:center;*z-index:1}#ftCon{height:100px;position:absolute;bottom:44px;text-align:center;width:100%;margin:0 auto;z-index:0;overflow:hidden}#ftConw{width:720px;margin:0 auto}body{font:12px arial;text-align:;background:#fff}body,p,form,ul,li{margin:0;padding:0;list-style:none}body,form,#fm{position:relative}td{text-align:left}img{border:0}a{color:#00c}a:active{color:#f60}.bg{background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_a7f1d98c.png);background-repeat:no-repeat;_background-image:url(http://s1.bdstatic.com/r/www/cache/static/global/img/icons_2df5fe5e.gif)}.bg_tuiguang_browser{width:16px;height:16px;background-position:-600px 0;display:inline-block;vertical-align:text-bottom;font-style:normal;overflow:hidden;margin-right:5px}.bg_tuiguang_browser_big{width:56px;height:56px;position:absolute;left:10px;top:10px;background-position:-600px -24px}
下面还有很多。。。。
开发一个较山寨的浏览器:根据HTTP协议,不难看出只要我们遵从http协议的格式向服务器发送信息,服务器就能向我们送回所请求的数据,只要我们能把这些数据解析好就可以实现浏览器的功能了,以下是一个利用了java的GUI编写的功能较为山寨的穷人版浏览器的代码:
package myclass;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.URL;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkEvent.EventType;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLFrameHyperlinkEvent;
public class MiniBrowser
extends JFrame
implements HyperlinkListener
{
private JButton backButton;
private JButton forwardButton;
private JTextField locationTextField;
private JEditorPane displayEditorPane;
private ArrayList<String> pageList = new ArrayList();
public MiniBrowser()
{
super("迷你浏览器");
setSize(640, 480);
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent paramAnonymousWindowEvent)
{
MiniBrowser.this.actionExit();
}
});
JMenuBar localJMenuBar = new JMenuBar();
JMenu localJMenu = new JMenu("文件");
localJMenu.setMnemonic(70);
JMenuItem localJMenuItem = new JMenuItem("退出", 88);
localJMenuItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent paramAnonymousActionEvent)
{
MiniBrowser.this.actionExit();
}
});
localJMenu.add(localJMenuItem);
localJMenuBar.add(localJMenu);
setJMenuBar(localJMenuBar);
JPanel localJPanel = new JPanel();
this.backButton = new JButton("< 返回");
this.backButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent paramAnonymousActionEvent)
{
MiniBrowser.this.actionBack();
}
});
this.backButton.setEnabled(false);
localJPanel.add(this.backButton);
this.forwardButton = new JButton("前进 >");
this.forwardButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent paramAnonymousActionEvent)
{
MiniBrowser.this.actionForward();
}
});
this.forwardButton.setEnabled(false);
localJPanel.add(this.forwardButton);
this.locationTextField = new JTextField(35);
this.locationTextField.addKeyListener(new KeyAdapter()
{
public void keyReleased(KeyEvent paramAnonymousKeyEvent)
{
if (paramAnonymousKeyEvent.getKeyCode() == 10) {
MiniBrowser.this.actionGo();
}
}
});
localJPanel.add(this.locationTextField);
JButton localJButton = new JButton("打开");
localJButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent paramAnonymousActionEvent)
{
MiniBrowser.this.actionGo();
}
});
localJPanel.add(localJButton);
this.displayEditorPane = new JEditorPane();
this.displayEditorPane.setContentType("text/html");
this.displayEditorPane.setEditable(false);
this.displayEditorPane.addHyperlinkListener(this);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(localJPanel, "North");
getContentPane().add(new JScrollPane(this.displayEditorPane), "Center");
}
private void actionExit()
{
System.exit(0);
}
private void actionBack()
{
URL localURL = this.displayEditorPane.getPage();
int i = this.pageList.indexOf(localURL.toString());
try
{
showPage(new URL((String)this.pageList.get(i - 1)), false);
}
catch (Exception localException) {}
}
private void actionForward()
{
URL localURL = this.displayEditorPane.getPage();
int i = this.pageList.indexOf(localURL.toString());
try
{
showPage(new URL((String)this.pageList.get(i + 1)), false);
}
catch (Exception localException) {}
}
private void actionGo()
{
URL localURL = verifyUrl(this.locationTextField.getText());
if (localURL != null) {
showPage(localURL, true);
} else {
showError("该地址无效");
}
}
private void showError(String paramString)
{
JOptionPane.showMessageDialog(this, paramString, "Error", 0);
}
private URL verifyUrl(String paramString)
{
if (!paramString.toLowerCase().startsWith("http://")) {
return null;
}
URL localURL = null;
try
{
localURL = new URL(paramString);
}
catch (Exception localException)
{
return null;
}
return localURL;
}
private void showPage(URL paramURL, boolean paramBoolean)
{
setCursor(Cursor.getPredefinedCursor(3));
try
{
URL localURL1 = this.displayEditorPane.getPage();
this.displayEditorPane.setPage(paramURL);
URL localURL2 = this.displayEditorPane.getPage();
if (paramBoolean)
{
int i = this.pageList.size();
if (i > 0)
{
int j = this.pageList.indexOf(localURL1.toString());
if (j < i - 1) {
for (int k = i - 1; k > j; k--) {
this.pageList.remove(k);
}
}
}
this.pageList.add(localURL2.toString());
}
this.locationTextField.setText(localURL2.toString());
updateButtons();
}
catch (Exception localException)
{
showError("迷你浏览器无法显示该页面");
}
finally
{
setCursor(Cursor.getDefaultCursor());
}
}
private void updateButtons()
{
if (this.pageList.size() < 2)
{
this.backButton.setEnabled(false);
this.forwardButton.setEnabled(false);
}
else
{
URL localURL = this.displayEditorPane.getPage();
int i = this.pageList.indexOf(localURL.toString());
this.backButton.setEnabled(i > 0);
this.forwardButton.setEnabled(i < this.pageList.size() - 1);
}
}
public void hyperlinkUpdate(HyperlinkEvent paramHyperlinkEvent)
{
HyperlinkEvent.EventType localEventType = paramHyperlinkEvent.getEventType();
if (localEventType == HyperlinkEvent.EventType.ACTIVATED) {
if ((paramHyperlinkEvent instanceof HTMLFrameHyperlinkEvent))
{
HTMLFrameHyperlinkEvent localHTMLFrameHyperlinkEvent = (HTMLFrameHyperlinkEvent)paramHyperlinkEvent;
HTMLDocument localHTMLDocument = (HTMLDocument)this.displayEditorPane.getDocument();
localHTMLDocument.processHTMLFrameHyperlinkEvent(localHTMLFrameHyperlinkEvent);
}
else
{
showPage(paramHyperlinkEvent.getURL(), true);
}
}
}
public static void main(String[] paramArrayOfString)
{
MiniBrowser localMiniBrowser = new MiniBrowser();
localMiniBrowser.setVisible(true);
}
}
以下是该浏览器访问百度的效果: