Java 网络编程四 C/S B/S(例:模拟浏览器、服务器、网络爬虫)

来源:互联网 发布:薛之谦淘宝店铺号 编辑:程序博客网 时间:2024/06/05 02:50

C/S 与 B/S

☆ C/S ( Client/Server ) 客户端和服务端的特点

1、客户端和服务端的软件都需要程序员进行编写。
2、客户端维护起来较为麻烦。
3、客户端的存在可以将一部分运算分离到客户端来运行,减轻了服务器端的压力。

☆ B/S ( Browse/Server ) 浏览器和服务端的特点

1、客户端不用程序员编写,直接使用系统中具备的浏览器软件作为客户端即可。程序员只需要编写服务器端就OK了。
2、维护起来也很容易,因为只要维护服务器即可。
3、所有的运算都在服务器端,相对压力较大。


下面通过几个练习理解一下B/S模式的底层socket通讯原理

1、自定义一个服务器,接收浏览器发来的信息。显示浏览器发送了什么信息,并向浏览器发送简单的网页信息。

package cn.hncu.net.bs;import java.io.BufferedReader;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;/** * @author<a href="mailto:794530831@qq.com">dragon_Dai</a> * @version 2017-8-14 下午7:27:41 * @filename MyServer.java *  * 模拟服务器,接收浏览器发送的信息,并向浏览器返回一个简单的网页信息(还没学习html) */public class MyServer {public static void main(String[] args) {ServerSocket server=null;try {server = new ServerSocket(80);} catch (IOException e1) {e1.printStackTrace();}if(server!=null){while(true){try {Socket s=server.accept();String ip=s.getInetAddress().getHostAddress();//获取向服务器请求的ip地址System.out.println(ip+":请求信息");//获取浏览器向服务器请求的信息//InputStream is=s.getInputStream();//byte bs[]=new byte[512];//int len=-1;//while((len=is.read(bs))!=-1){//System.out.print(new String(bs, 0, len));//}//BufferedReader br2=new BufferedReader(new InputStreamReader(s.getInputStream()));//String str=null;//while((str=br2.readLine())!=null){//System.out.println(str);//}//上面两种方法获取浏览器向服务器请求的信息的方式都是不可取的,因为无法判断结束,浏览器有它自己的判断方式。//只能一次性全部读取.//获取浏览器向服务器请求的信息byte buf[]=new byte[512];InputStream in = s.getInputStream();int len = in.read(buf);String txt = new String(buf,0,len);System.out.println(txt);//返还给浏览器信息//发送的请求需要浏览器认识,仍然需要采用http协议的请求头PrintWriter pw = new PrintWriter(s.getOutputStream(),true);//pw.println("HTTP/1.1 200 OK");//HTTTP协议中的响应行//pw.println("Content-Type: text/html;charset=UTF-8");//设置编码//pw.println();//协议请求头结束之后,需要一个空行//上诉协议的请求头我加入到了html文件中。//接下来返还一个网页的信息(.html)//源:从文件中读取BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("dragon.html")));String str2=null;while((str2=br.readLine())!=null){pw.println(str2);//在写入到socket中}System.out.println("------------------------over");//关流in.close();pw.close();br.close();s.close();} catch (IOException e) {e.printStackTrace();}}}}}
dragon.html

HTTP/1.1 200 OKContent-Type: text/html;charset=UTF-8<!DOCTYPE html><html><h2>欢迎你....</h2><font size=15 color='red'><table border=2 cellspacing=0 bordercolor='black'><tr> <td>姓名</td> <td>年龄</td> </tr><tr> <td>dragon</td> <td>20</td> </tr><tr> <td>龙</td> <td>19</td> </tr></table><br/>链接:<a href='http://blog.csdn.net/dragon_dai_2017'>我的博客</a></font></html>
1:当使用IE浏览器 访问127.0.0.1(访问一次)时:服务器记录信息如下:

127.0.0.1:请求信息GET / HTTP/1.1Accept: text/html, application/xhtml+xml, image/jxr, */*Accept-Language: zh-CNUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like GeckoAccept-Encoding: gzip, deflateHost: 127.0.0.1DNT: 1Connection: Keep-Alive------------------------over
2:当使用360浏览器访问127.0.0.1(访问一次)时:服务器记录信息如下:

127.0.0.1:请求信息GET / HTTP/1.1Host: 127.0.0.1Connection: keep-aliveCache-Control: max-age=0Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Encoding: gzip, deflate, sdch, brAccept-Language: zh-CN,zh;q=0.8Cookie: __guid=96992031.1350441646852180200.1502715904461.7183; monitor_count=27------------------------over127.0.0.1:请求信息GET /favicon.ico HTTP/1.1Host: 127.0.0.1Connection: keep-alivePragma: no-cacheCache-Control: no-cacheUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36Accept: image/webp,image/*,*/*;q=0.8Referer: http://127.0.0.1/Accept-Encoding: gzip, deflate, sdch, brAccept-Language: zh-CN,zh;q=0.8Cookie: __guid=96992031.1350441646852180200.1502715904461.7183; monitor_count=28------------------------over
同样是访问一次,360浏览器记录2次信息。IE浏览器记录一次信息。这问题说明了不同的浏览器之间的机制不一样。

使用多线程如下:

package cn.hncu.net.bs;import java.io.BufferedReader;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;/** * @author<a href="mailto:794530831@qq.com">dragon_Dai</a> * @version 2017-8-14 下午8:51:51 * @filename MyServer2.java *  * 模拟服务器,接收浏览器发送的信息,并向浏览器返回一个简单的网页信息(还没学习html) * 多线程版本 */public class MyServer2 {public static void main(String[] args) {try {ServerSocket server=new ServerSocket(80);while(true){Socket s=server.accept();new Thread(new MyRun(s)).start();}} catch (IOException e) {e.printStackTrace();}}}class MyRun implements Runnable{private Socket s;public MyRun(Socket s) {this.s=s;}@Overridepublic void run() {String ip=s.getInetAddress().getHostAddress();System.out.println(ip+"请求信息");//获取浏览器的请求信息try {//BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));//String str=null;//while((str=br.readLine())!=null){//System.out.println(str);//}//只能一次性把浏览器请求的信息全部获取。byte buf[]=new byte[512];InputStream in = s.getInputStream();int len = in.read(buf);String txt = new String(buf,0,len);System.out.println(txt);//返还给浏览器信息//发送的请求需要浏览器认识,仍然需要采用http协议的请求头PrintWriter pw = new PrintWriter(s.getOutputStream(),true);//接下来返还一个网页的信息(.html)//源:从文件中读取BufferedReader br2=new BufferedReader(new InputStreamReader(new FileInputStream("dragon.html")));String str2=null;while((str2=br2.readLine())!=null){pw.println(str2);//在写入到socket中}//关流in.close();pw.close();br2.close();s.close();} catch (IOException e) {e.printStackTrace();}}}

2、模拟一个浏览器客户端向服务器发请求,接收并显示响应消息。

package cn.hncu.net.bs;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.Socket;import java.net.UnknownHostException;/** * @author<a href="mailto:794530831@qq.com">dragon_Dai</a> * @version 2017-8-14 下午6:29:21 * @filename MyBrowse.java *  * 简单模拟一下浏览器,向服务器发送请求,并且接收来自服务器的响应信息。 */public class MyBrowse {public static void main(String[] args) {try {//浏览器为每个服务器默认添加的端口号是:80Socket s=new Socket("news.baidu.com", 80);//向服务器发送请求  PrintWriter pw=new PrintWriter(s.getOutputStream(),true);//自动刷缓存//发送的请求需要浏览器认识,所以要采用http协议的请求头pw.println("GET / HTTP/1.1");//http协议中的响应行pw.println("Accept: text/html, application/xhtml+xml, */*");pw.println("Host:news.baidu.com");pw.println("Connection: Keep-Alive");pw.println();//协议请求头结束之后需要一个空行//接收服务器的响应信息BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));String str=null;while((str=br.readLine())!=null){System.out.println(str);}//关流pw.close();br.close();s.close();} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}
运行结果:

HTTP/1.1 200 OKConnection: keep-aliveContent-Type: text/html;charset=utf-8Date: Mon, 14 Aug 2017 15:57:17 GMTP3p: CP=" OTI DSP COR IVA OUR IND COM "Server: ApacheSet-Cookie: BAIDUID=37A6CC4CA8CF47D6D1BB6995D029805E:FG=1; expires=Tue, 14-Aug-18 15:57:17 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1Tracecode: 34374410850742441738081423Tracecode: 34374114540907268106081423Vary: Accept-EncodingVary: Accept-EncodingTransfer-Encoding: chunkede1a<!doctype html>...下面是网页的源代码信息......
3、网络蜘蛛,收集网页中的邮箱地址信息。

package cn.hncu.net.spider;import java.io.BufferedReader;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.MalformedURLException;import java.net.URL;import java.util.regex.Matcher;import java.util.regex.Pattern;import org.junit.Test;/** * @author<a href="mailto:794530831@qq.com">dragon_Dai</a> * @version 2017-8-14 下午7:58:38 * @filename SpiderDemo.java *  * 简单的网络爬虫(蜘蛛),爬取网页中邮箱信息 *   没有算法。。 */public class SpiderDemo {//1.先在本地的一个文件中测试一下看能否爬取到邮箱地址信息@Testpublic void demo1(){try {BufferedReader br=new BufferedReader(new FileReader("mail.html"));//正则表达式//String regex="//w+@//w+(//.//w+)+";错误String regex ="\\w+@\\w+(\\.\\w+)+";//工具Pattern p=Pattern.compile(regex);String str=null;while((str=br.readLine())!=null){Matcher m = p.matcher(str);//用str去匹配 正则表达式while(m.find()){//如果匹配成功System.out.println(m.group());//输出匹配结果}}br.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}//2.到网络页面爬取邮箱地址@Testpublic void demo2(){try {URL url=new URL("http://acm.hdu.edu.cn");//url.openStream() 打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。BufferedReader br=new BufferedReader(new InputStreamReader(url.openStream()));//正则表达式String regex="\\w+@\\w+(\\.\\w+)+";//工具Pattern p=Pattern.compile(regex);String str=null;while((str=br.readLine())!=null){Matcher m=p.matcher(str);while(m.find()){System.out.println(m.group());}}//关流br.close();} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}
demo1:

mail.html

<html><head><title>用于演示网络爬虫的网页</title></head><body><p>☆ C/S ( Client/Server ) 客户端和服务端的特点1、客户端和服务端的软件都需要程序员进行编写。 2、客户端维护起来较为麻烦。(缺陷) 3、客户端的存在可以将一部分运算分离到客户端来运行,减轻了服务器端的压力。(优势)☆ B/S ( Browse/Server ) 浏览器和服务端的特点1、客户端不用程序员编写,直接使用系统中具备的浏览器软件作为客户端即可。程序员只需要编写服务器端就OK了。 2、维护起来也很容易,因为只要维护服务器即可。(优势) 3、所有的运算都在服务器端,相对压力较大。(缺陷)</p>12345abc@sina.com<br/>姓名:<input type="text" name="name"/><input type="hidden" value="abc12345@126.com" />  </br><a href="794530831@qq.com">联系站长</a></body></html>
爬取结果:

12345abc@sina.comabc12345@126.com794530831@qq.com
demo2:

爬取结果:

acm@hdu.edu.cnacm@hdu.edu.cngjavac@gmail.comgl8997@gmail.com

阅读全文
1 0