基于socket的http的请求监听程序的设计本科学位论文.doc
简单应用系统学年设计 任务书 学 院计算机与信息工程学院专 业网络工程课程名称简单应用系统题 目基于Socket的HTTP请求监听程序的设计实现完成期限自2015年7月9日 至2015年8月30日 共8周内容及任务一、项目的目的 用java编写一个监听程序,监听指定的端口,通过浏览器如http:/localhost:7777来访问时,可以把请求到的内容记录下来,记录可以存文件,sqlit,mysql数据库,然后把接受到的信息在浏览器中显示出来二、项目任务的主要内容和要求监听指定的端口,通过浏览器如http:/localhost:7777来访问时,可以把请求到的内容记录下来,记录可以存文件,sqlit,mysql数据库,然后把接受到的信息在浏览器中显示出来。实现本程序需要了解网络基础知识、网络安全基础知识,掌握C/S结构的工作特点,掌握高级语言及网络编程知识,可以选择Visual C+、C或Java等语言实现。三、项目设计(研究)思路1.用到的主要技术: Socket,线程,数据库,IO操作 2.设计思路: 我们如何来设计这个小系统,这个系统包含三部分的内容,一个是监听端口,二是记录日志,三是数据回显,端口监听第一想到的就是Socket编程了,数据回显也是一样的,无非是把当前请求客户端的socket获取到,然后把消息通过流输出出去,日志的记录因为是要多种实现策略,这里我们使用了一个观察者模式来实现,服务器可以添加任意多个观察着,因此有着很灵活的扩展性,在实例程序中我们分别提供了ConsoleRecordHandler-直接把获取到的信息打印到控制台,和存放数据库的方式-MysqlRecordHandler,当然你也可以分别提供基于文件的实现。首先来看我们系统的类图四、具体成果形式和要求学年设计说明书和相关程序;进度安排起止日期工作内容7.9分析课题,寻找相关资料。8.25-8.27学习相关知识,打下基础。8.288.30设计解决方案并调试。主要参考资料1Windows防火墙与网络封包截获技术 朱雁辉 编著 电子工业出版社2监听与隐藏 求实科技 谭思亮 编著 人民邮电出版社3计算机网络安全基础 袁津生 吴砚农 编著 人民邮电出版社4Visual C+ 6.0 技术内幕 美David J.Kruglinski, Scot Wingo ,George Shepherd编著 希望图书创作室 译 北京希望电子出版社指导教师意见(签字): 年 月 日系(教研室)主任意见(签字): 年 月 日 简单应用系统学年 设计说明书(或论文)(封面)学院名称: 计算机与信息工程学院 班级名称: 网络工程1班 学生姓名: 学 号: 题 目: 基于Socket的HTTP请求监听程序的设计实现 指导教师姓 名: 陈海宝 起止日期: 2015.7.92015.8.30 目录1.选题背景12.设计理念1 2.1.课题要求1 2.2课题分析22.3课题解决方案23. 过程论述23.1概要设计23.2启动MySQL,创建数据库和表74.结果分析134.1测试结果135.总结19附录20致谢28第一部分:正文部分一、选题背景随着计算机的发展,越来越多的技术体现在现有的网络布局当中,并且起到了引领计算机科技领域的作用。为了让学生了解基本网络构建的相关知识,理解客户机,服务器的运行原理,因而选用了基于Socket的HTTP的请求监听程序的设计这一课题来让学生自主的去理解这些网络知识。为了实现这一课题,让本地机既作为客户机,又作为服务器来使用,能够让学生深刻了解服务器是如何响应客户端的请求,并且监听指定的端口的。在此同时,也能让学生掌握住一些基本的简单的设计网页的HTML语言和JSP语言的知识。二、设计理念1.课题要求监听指定的端口,通过浏览器如http:/localhost:7777来访问时,可以把请求到的内容记录下来,记录可以存文件,sqlit,mysql数据库,然后把接受到的信息在浏览器中显示出来。2.课题分析首先,监听指定端口可以采用监听服务器的端口号来实现;通过浏览器来访问并把信息在浏览器中显示出来,这个可以建立一个简单的网站,然后由本机的客户端来对服务器进行访问2,并且把访问的内容通过服务器发送给本机的客户端,也就是采用C/S模式;记录可以存文件或者是数据库这一点,可以通过JDBC的方式连接数据库,然后更新里面的内容。3.课题解决方案(1)相关软件:Tomcat6.0(或6.0版本以上)、MySQL5.0数据库(其他数据库也可)。(2)设计思路:首先,安装并启动以上两个软件,在数据库中创建一个Student数据库和两张表(可以用MySQL相关的编辑软件制作表):user表,information表,在information表中加入一些数据;其次,用txt文本编写JSP文件和Tag文件(也可以下载相关的JSP文件编辑软件),在Tag文件中添加数据库连接语句;最后,用浏览器进行测试。(3)流程图如下:登录用户名是否存在开始登录成功查询所查信息是否存在显示信息结束注册重建数据库信息是是否否图2-3-1 总体流程图三、过程论述3.1 概要设计httpServe类是我们的核心类,他实现了Runnable接口,因此有着更高的性能,在循环中不断的去轮询指定端口,构造方法比较简单,只需要一个要监听的端口号即可,还有两个用于触发监听和停止程序运行的方法stop()&start(),这两个方法也比较简单,只是简单的给标志位赋值即可,我们这个程序是基于Oserver模式的简化版本,HttpServer本身是一个被观察的对象(Subject),当这个Subject有变化时(获取到客户端请求时)要通知监听器(我们的RecordHandler)去作操作(写数据库还是写文件或是直接控制台输出),极大增加了系统的灵活性和易测试性(1) HttpServer类代码package com.crazycoder2010.socket; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import .ServerSocket; import .Socket; import java.sql.Date; import java.util.ArrayList; import java.util.List; /* * 服务器监听对象,对某个端口进行监听,基于线程的实现 * * author Kevin * */ public class HttpServer implements Runnable /* * 服务器监听 */ private ServerSocket serverSocket; /* * 标志位,表示当前服务器是否正在运行 */ private boolean isRunning; /* * 观察者 */ private List<RecordHandler> recordHandlers = new ArrayList<RecordHandler>(); public HttpServer(int port) try serverSocket = new ServerSocket(port); catch (IOException e) e.printStackTrace(); public void stop() this.isRunning = false; public void start() this.isRunning = true; new Thread(this).start(); Override public void run() while (isRunning) /一直监听,直到受到停止的命令 Socket socket = null; try socket = serverSocket.accept();/如果没有请求,会一直hold在这里等待,有客户端请求的时候才会继续往下执行 / log BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(socket.getInputStream();/获取输入流(请求) StringBuilder stringBuilder = new StringBuilder(); String line = null; while (line = bufferedReader.readLine() != null && !line.equals("") /得到请求的内容,注意这里作两个判断非空和""都要,只判断null会有问题 stringBuilder.append(line).append("/n"); Record record = new Record(); record.setRecord(stringBuilder.toString(); record.setVisitDate(new Date(System.currentTimeMillis(); notifyRecordHandlers(record);/通知日志记录者对日志作操作 / echo PrintWriter printWriter = new PrintWriter( socket.getOutputStream(), true);/这里第二个参数表示自动刷新缓存 doEcho(printWriter, record);/将日志输出到浏览器 / release printWriter.close(); bufferedReader.close(); socket.close(); catch (IOException e) e.printStackTrace(); /* * 将得到的信写回客户端 * * param printWriter * param record */ private void doEcho(PrintWriter printWriter, Record record) printWriter.write(record.getRecord(); /* * 通知已经注册的监听者做处理 * * param record */ private void notifyRecordHandlers(Record record) for (RecordHandler recordHandler : this.recordHandlers) recordHandler.handleRecord(record); /* * 添加一个监听器 * * param recordHandler */ public void addRecordHandler(RecordHandler recordHandler) this.recordHandlers.add(recordHandler); (2) Record类非常简单,只是作为参数传递的对象来用package com.crazycoder2010.socket; import java.sql.Date; public class Record private int id; private String record; private Date visitDate; public int getId() return id; public void setId(int id) this.id = id; public String getRecord() return record; public void setRecord(String record) this.record = record; public Date getVisitDate() return visitDate; public void setVisitDate(Date visitDate) this.visitDate = visitDate; (3) RecordHandler接口,统一监听接口,非常简单package com.crazycoder2010.socket; /* * 获取到访问信息后的处理接口 * author Kevin * */ public interface RecordHandler public void handleRecord(Record record); (4) ConsoleRecordHandler实现,直接System打印输出,在我们作测试时非常有用package com.crazycoder2010.socket; public class ConsoleRecordHandler implements RecordHandler Override public void handleRecord(Record record) System.out.println(""); System.out.println(record.getRecord(); (5) MysqlRecordHandler,数据库实现,定义了要对数据库操作所需要的几个基本属性url,username,password,加载驱动的程序我们放在了静态代码短中,这个东东嘛,只要加载一次就ok了package com.crazycoder2010.socket; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; public class MysqlRecordHandler implements RecordHandler static try Class.forName("com.mysql.jdbc.Driver"); catch (ClassNotFoundException e) e.printStackTrace(); private static final String NEW_RECORD = "insert into log(record,visit_date) values (?,?)" /* * 数据库访问url */ private String url; /* * 数据库用户名 */ private String username; /* * 数据库密码 */ private String password; public void setUrl(String url) this.url = url; public void setUsername(String username) this.username = username; public void setPassword(String password) this.password = password; Override public void handleRecord(Record record) Connection connection = ConnectionFactory.getConnection(url, username, password); PreparedStatement preparedStatement = null; try preparedStatement = connection.prepareStatement(NEW_RECORD); preparedStatement.setString(1, record.getRecord(); preparedStatement.setDate(2, record.getVisitDate(); preparedStatement.executeUpdate(); catch (SQLException e) e.printStackTrace(); finally ConnectionFactory.release(preparedStatement); ConnectionFactory.release(connection); (6)ConnectionFactory类,我们的数据库连接工厂类,定义了几个常用的方法,把数据库连接独立到外部单独类的好处在于,我们可以很灵活的替换连接的生成方式-如我们可以从连接池中获取一个,而我们的数据库操作却只关注Connection本身,从而达到动静分离的效果package com.crazycoder2010.socket; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; /* * 创建数据库连接的工厂类 * * author Kevin * */ public class ConnectionFactory public static Connection getConnection(String url, String username, String password) try return DriverManager.getConnection(url, username, password); catch (SQLException e) e.printStackTrace(); return null; /* * 释放连接 * * param connection */ public static void release(Connection connection) if (connection != null) try connection.close(); connection = null; catch (SQLException e) e.printStackTrace(); /* * 关闭查询语句 * * param preparedStatement */ public static void release(PreparedStatement preparedStatement) if (preparedStatement != null) try preparedStatement.close(); preparedStatement = null; catch (SQLException e) e.printStackTrace(); (7) init.sql我们的数据库建表脚本,只是为了演示,一个表就好CREATE TABLE logs.log ( id INT(10) NOT NULL AUTO_INCREMENT, record VARCHAR(1024) NOT NULL, visit_date DATETIME NOT NULL, PRIMARY KEY (id) ) ENGINE = MyISAM; (8) AppLuancher类,是时候把这几个模块高到一起跑起来的时候了,我们首先创建了一个服务器端,然后给服务器创建了两个监听器,然后启动服务器,这个时候我们的HttpServer已经开始监听7777端口了! package com.crazycoder2010.socket; public class AppLauncher /* * param args */ public static void main(String args) HttpServer httpServer = new HttpServer(7777); httpServer.addRecordHandler(new ConsoleRecordHandler(); httpServer.addRecordHandler(createMysqlHandler(); httpServer.start(); private static RecordHandler createMysqlHandler() MysqlRecordHandler handler = new MysqlRecordHandler(); handler.setUrl("jdbc:mysql:/localhost:3306/logs"); handler.setUsername("root"); handler.setPassword(""); return handler; (9)打开浏览器,输入http:/localhost:7777我们看到控制台输出了一堆的文字GET / HTTP/1.1Host: localhost:7777Connection: keep-aliveCache-Control: max-age=0User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127 Safari/534.16Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5Accept-Encoding: gzip,deflate,sdchAccept-Language: zh-CN,zh;q=0.8Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3 3.2 MySQL,创建数据库和表图3-2-2 输入数据图3-2-1 创建表创建Student数据库,user表和information表。图3-2-2 输入数据图3-2-3 显示表内信息四、结果分析1.开启服务器后,输入地址(这里的端口号选用为8080),运行网页,结果如下:(1)首页图4-1-1 首页这就表示index.jsp文件成功运行。(2)用户注册图4-1-2 注册界面图4-1-3 数据库显示register.jsp文件成功运行,这里我输入了用户名:Lucy,密码为123456。查看数据库中的user表。(3)用户登录图4-1-4 登录界面这表示Lucy已经成功登陆,当密码错误或者是用户名不存在时,会出现以下错误提示:图4-1-5 登录失败(4)学生查询图4-1-6 查询信息这里是将事先的infortmation表中的信息表示出来。图4-1-7 显示数据库信息至此,整个系统运行顺利。五、结论(或总结)这次整个的基于Socket的HTTP请求监听程序基本满足了学年设计的要求,能够很好地对本机指定的端口进行监听,然后通过浏览器将所要返回的信息一一返回给客户机。通过本次学年设计,使我对计算机网络中的C/S模式有了更深入的了解,但是还需加强实践。此外,在本次学年设计中,我明白了自学能力的重要性,设计思路是前提,只有有了完整的思路才能知道自己下一步应该做什么,其次,良好的编程基础也是关键,测试与调整也是在做系统的过程中必不可少的环节。在此过程中,我深深感觉到这些东西的重要性和实用性。通过这段时间的自学,我对网页制作的基础知识有了很好的掌握5,这对我以后的网络编辑会有一个很大的用处,学之所思,思之所用,用之所得,这就是我最大的感悟。第三部分:参考文献1 谢希仁.计算机网络(第六版).北京:电子工业出版社.2011.2 满昌勇.计算机网络基础.北京:清华大学出版社.2010.3 赵生慧.Java面向对象程序设计(第二版).北京:中国水利水电出版社.2010.4 张跃平 耿祥义.JSP程序设计.北京:清华大学出版社.5 Bill Scott/Theresa Neil.Web界面设计.北京:电子工业出版社.学生签名: 填表日期: 年 月 日第四部分: 指导教师评语第五部分:成绩评定指导教师签名: 填表日期: 年 月 日