7、自定义图形界面浏览器-Tomcat服务端
那么大家接下来,刚才咱们做了个DOS命令行,咱是不是可以做个图形化界面。
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
class MyIEByGUI{
//1,定义窗体组件
private Frame f;
private TextField tf;
private Button b;
private TextArea ta;
private Dialog d;
private Label dl;
private Button db;
MyIEByGUI(){
init();
}
public void init(){
//2,设置窗体组件
f=new Frame("my window");
f.setBounds(300,100,700,500);
f.setLayout(new FlowLayout());
//文本框,按钮,文本域
tf=new TextField(60);
f.add(tf);
b=new Button("转到");
f.add(b);
ta=new TextArea(25,70);
f.add(ta);
//3,添加事件
myEvent();
//4,显示窗体
f.setVisible(true);
}
//窗体事件
public void myEvent(){
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
//点击转到按钮显示文本
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
try{
showDir();
}catch(Exception ex){
throw new RuntimeException("上传失败");
}
}
});
//敲Enter键显示文本
tf.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
if(e.getKeyCode()==KeyEvent.VK_ENTER)
try{
showDir();
}catch(Exception ex){
throw new RuntimeException("上传失败");
}
}
});
}
private void showDir()throws IOException{
ta.setText("");
String url=tf.getText();
int index1=url.indexOf("//")+2;
int index2=url.indexOf("/",index1);
String str=url.substring(index1,index2);
String[] arr=str.split(":");
String host=arr[0];
int port=Integer.parseInt(arr[1]);
String path=url.substring(index2);
ta.setText(host+"..."+port+"..."+path);
//1,定义码头
Socket s=new Socket(host,port);
//2,定义输出流
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
out.println("GET "+path+" HTTP/1.1");
out.println("Accept: */*");
out.println("Accept-Language: zh-CN");
out.println("User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)");
out.println("Host: 10.2.172.93:11001");
out.println("Connection: Keep-Alive");
out.println();
out.println();
//3,定义接收服务端流
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len=0;
while((len=in.read(buf))!=0){
String line=new String(buf,0,len);
ta.append(line+"\r\n");
}
s.close();
}
public static void main(String[] args){
new MyIEByGUI();
}
public static void sop(Object obj){
System.out.println(obj);
}
}
完事了,就差数据解析了,但是数据我们一样获取到。
等下一节,咱再封装一下,咱写百度新浪一回车,百度新浪数据都拿到,就是解析不了。
浏览器强大就强大在它里面挂了N多解析引擎。html解析、css解析、javascript解析,N多内置引擎很吊。
至于socket,它能做,咱也能做。但有个问题浏览器的数据咱是不是多了一部分。
浏览器的是应用层的部分,但很遗憾咱走的是传输层,咱把传输层的数据全都拿过来了,
而咱浏览器把HTTP协议封装的信息是不是给拆掉了,数据的向上传输到应用层的时候是不是要拆包,对吧,浏览器把那个包给拆了。
咱没拆,下一节就把它拆了。跟浏览器一模一样。咱是不是刚才解析url要死,这事负责吧,那java是不是会提供个对象给我们解决啊。
待会下一节,咱就学一个对象,把这件事给解决了,要多easy就有多easy。你不写对象是最es
8、URL-URLConnection
这上一节,咱做了个小程序,咱输入个url可以去访问这个服务端是吧。
那么服务端tomcat服务器给我们发回来了一些信息。
这些信息当中啊,除了信息的主体之外,是不是响应头信息和数据体之间有空行。
那么这个信息大家注意到,为什么浏览器访问完以后就没有这个信息呢。
这就是小问题了,首先我们分析一点就是,原来咱用的是传输层的协议啊,
我们就获取到了服务层给我们发过来所有数据,并把数据都展示在了文本区域当中。
而浏览器做的事情将这些消息做了个解析,把应用层协议消息的部分解析完拆包扔掉了,
把正文数据主体部分显示在了自己接收的区域范围内。
那么大家看,上一章咱写的代码稍微有点麻烦,麻烦在哪?
就是我们对url数据其实是进行了获取其中的每一部分,获取完了,
采取封装对象,向服务器短发送我们的请求资源。很麻烦。
那么思考另外一问题,像这样的url路径是不是很常见,而且它里面包含东西非常多。
所以相对复杂的东西我们是不是要去找有没有相对应的对象,如果有这个对象就拿来用。
如果没有,我们也有将上一节的代码中的url封装成一个对象,以便下次来用。
应用层有个HTTP协议,把HTTP头部分数据去掉了,把数据主体返回来了。
import java.net.*;
class URLDemo{
public static void main(String[] args)throws MalformedURLException{
URL url=new URL("http://10.2.172.93:8080/myweb/demo.html?name=hh&age=30");
sop("getProtocol:"+url.getProtocol());
sop("getHost:"+url.getHost());
sop("getPort:"+url.getPort());
sop("getPath:"+url.getPath());
sop("getFile:"+url.getFile());
sop("getQuery:"+url.getQuery());
}
public static void sop(Object obj){
System.out.println(obj);
}
}
import java.net.*;
import java.io.*;
class URLConnectionDemo{
public static void main(String[] args)throws Exception{
URL url=new URL("http://10.2.172.93:8080/myweb/demo.html");
URLConnection conn=url.openConnection();
sop(conn);
InputStream in=conn.getInputStream();
byte[]buf=new byte[1024];
int len=in.read(buf);
sop(new String(buf,0,len));
}
public static void sop(Object obj){
System.out.println(obj);
}
}
将上一节中的showDir方法内部修改:
private void showDir()throws IOException{
ta.setText("");
String url1=tf.getText();
URL url=new URL(url1);
URLConnection conn=url.openConnection();
sop(conn);
InputStream in=conn.getInputStream();
byte[]buf=new byte[1024];
int len=in.read(buf);
ta.setText(new String(buf,0,len));
}
做完了,但很遗憾不能对接收到服务端的数据进行解析。
9、小知识点
简单介绍点小东西,大家会发现我们在学socket时,它是不是有一个向主机发送空参数的一个构造函数。
SocketAddress与InetAddress的区别,看SocketAddress的子类InetSocketAddress吧。InetAddress封装的是IP地址,InetSocketAddress封装的是(IP地址+端口号)。
backlog是限制人数参数。
10、域名解析
接下来,我们讲一点网络知识,比较重点的一部分。
我在进行浏览器写入一个网址访问某一台主机的时候,它到底做了什么事情。
http://10.2.172.93:8080/myweb/demo.html浏览器在进行这句话解析以后是不是要先看协议啊。
看完这个协议后,会去启动相对应的协议并解析后面的主机和后面的端口。
http://www.sina.com.cn
想要主机名翻译成IP地址,需要域名解析,需要DNS域名解析服务器。
解析sina主机名对应的IP地址,主机名和IP地址映射的关系。
假如你是电信的宽带,你去访问联通的DNS,可不可以?当然可以。你访问美国的DNS都没问题。
但,有可能你去请求美国时,访问时间过长,过时了,那就失败了。
还有你去访问美国的DNS服务器(在我们的本地连接里的IP4属性修改里),可能没有你想要的网址。
还有如果走http://127.0.0.1:8080(http://localhost:8080)为什么这两个是对应的。
其实127和localhost映射关系就在本机上C:\windows\system32\drivers\etc\hosts
其实不难发现访问www.sina.com会先找本机hosts,这主机名有没有对应的地址,如有就会反馈到浏览器。
这有什么用?例如:某个软件启动时去访问你是否注册了软件,是否是正版的,
那么你可以可以在这里添加该软件登录到的网址指向127.0.0.1,不让该软件更新。