一个简单的即时通讯工具的设计与开发
摘 要
即时通讯(Instant Messaging)是目前Internet上最为流行的通讯方式,各种各样的即时通讯软件也层出不穷;服务提供商也提供了越来越丰富的通讯服务功能。Java是当前比较流行的开发语言之一,它有着自己的易用特点与性能优势,比如跨平台、安全性、多线程、网络Socket编程、数据流概念等方面,因此通过对开源即时通讯LinuxQQ的研究和分析,基于Java语言和J2EE规范设计了一个即时通讯工具JICQ (Java for I seek you),并对其体系结构、构成模块及系统关键技术进行了分析与设计。在系统设计与建模过程中,使用了UML和面向对象的分析、设计方法,并使用Rose作为建模工具;本系统基于j2se1.5,j2ee1.4,使用Eclipse等作为开发工具,在开发过程中用到了时下流行的重构开发方法,优化了系统的设计。力图使系统具有安全、高效、实用、支持在不同系统平台运行等特点。
关键词:即时通讯;多线程;SOCKET编程;JSP
目录
一个简单的即时通讯工具的设计与开发
1引言
1.1 项目开发背景
1.1.1 项目背景
1.1.2 技术背景
1.2 该系统设计的意义
2相关理论及基础技术与开发平台
2.1 即时通讯应用工作原理分析
2.2所用技术
2.3工具及开发平台
2.4 系统配置要求
3系统体系结构的设计
3.1 需求描述
3.2系统架构设计
3.3 系统的总体功能设计
3.3.1总体功能设计
3.3.2注册模块设计
3.3.3 登录模块设计
3.3.4用户间交互模块设计
3.4数据库设计
3.4.1数据库物理模型
3.4.2数据字典
4系统实现
4.1网络通讯编码实现
4.1.1聊天客户端部分代码
4.1.2服务器端监听与转发消息代码
4.1.3服务端单线程上线处理代码
4.2 系统运行的效果图
4.2.1 登录界面
4.2.2 主界面
4.2.3 群聊天界面
4.2.4 好友聊天界面
4.2.5 好友查找界面
4.3注册模块的实现
4.3.1 数据库连接
4.3.2 字符编码过滤器的核心代码
4.4 注册模块运行效果图
4.4.1 主页面
4.4.2 注册页面
5 系统测试与运行
结 论
参考文献
致 谢
1引言
1.1 项目开发背景
1.1.1 项目背景
“即时通信产品”最早的创始人是三个以色列青年,是他们在1996年做出来的,取名叫ICQ( I seek you)。随后,腾迅QQ抓住IM的大好机遇,在中国迅速崛起并垄断即时通讯市场。自从腾迅的QQ在中国即时通讯行业垄断后,即时通讯的产品在IT行业可谓雨后春笋,层出不穷,目前,Windows平台方面的即时通讯已经很多,但是其他系统比如Linux平台,虽然有类似QQ方面的一些产品,比如LinuxQQ,Lunaqq,但数量毕竟不多且功能界面等都还不是很理想,鉴于此种情况,我们开发了基于Java语言的即时通信系统(JICQ),该系统是以J2SE(Java 2 Standard Edition)语言实现的网络即时通信工具,包括服务器端和客户端,可以在企业内部网络和互联网上运行,同时具有Java应用的跨平台特性,方便运行在各个系统之上。该系统具有相对比较漂亮的界面以及类似于QQ的很多功能,比如可以和好友进行交流以及离线发送与好友管理、可以加入不同的群,即时发送、即时回复等功能。
1.1.2 技术背景
技术上采用sun公司的java语言,该语言有很多有点,比如多线程、网络流概念、异常捕获处理、安全性以及速度与性能等方面,并且具有可以一次编写、到处运行的跨平台优点。
多线程:多线程是这样一种机制,它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立,线程又称为轻量级进程,多线程技术允许你在一个应用程序中启动多个执行轻量程序,使多段程序同时竞争CPU资源,从而提高系统效率。而对于网络通讯工具来说,多线程的特性是必须的,不仅是为了效率,而且可以实现同时处理多个请求。
网络流:java中的网络通讯以及文件的读取都是以一种流的概念来理解的,这样,网络上数据的传输其实就等同于看成一台机器上文件的读取,有利于理解与编写运用程序,java类库中提供了丰富的IO流类资源以及网络编程类资源,软件开发人员可以很方便的编写网络应用程序。
例外处理:Java通过面向对象的方法来处理例外。在一个方法的运行过程中,如果发生了例外,则这个方法生成代表该例外的一个对象,并把它交给运行时系统,运行时系统寻找相应的代码来处理这一例外。我们把生成例外对象并把它提交给运行时系统的过程称为抛弃(throw)一个例外。运行时系统在方法的调用栈中查找,从生成例外的方法开始进行回朔,直到找到包含相应例外处理的方法为止,这一个过程称为捕获(catch)一个例外。所以,java的例外处理使非常方便的。
跨平台:Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用模式Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。
1.2 该系统设计的意义
伴随着当今互联网迅速发展,网上通讯成为一种必不可少的通讯习惯,该系统的设计就是为了实现在互联网上的即时通讯,它是利用当今最为流行的java编程语言来实现即时通讯工具的雏形,同时在系统开发过程中所用的都是java常用的技术或者难点,比如用java的swing怎么去做一个界面美观的应用程序、java的网络编程技术的原理与应用、以及如何根据J2EE规范去开发一个基于Jsp和Servlet的Web应用等关键技术。通过设计和开发该系统,使自己所学的理论知识得到实践应用,也对即时通讯软件的通讯原理有了比较深刻的认识,大大的提高了自己的动手能力和解决问题的能力,为今后工作打下坚实的基础。
2相关理论及基础技术与开发平台
2.1 即时通讯应用工作原理分析
我们经常听到TCP/IP和UDP(用户数据报协议)这两个术语,它们都是建立在更低层的IP协议上的两种通讯传输协议。前者是以数据流的形式,将传输数据经分割、打包后,通过两台机器之间建立起的虚电路,进行连续的、双向的、严格保证数据正确性的文件传输协议。而后者是以数据报的形式,对拆分后的数据的先后到达顺序不做要求的文件传输协议。
QQ就是使用UDP协议进行发送和接收“消息”的。当你的机器安装了OICQ以后,实际上,你既是服务端(Server),又是客户端(Client)。当你登录OICQ时,你的OICQ作为Client连接到腾讯公司的主服务器上,当你“看谁在线”时,你的OICQ又一次作为Client从QQ Server上读取在线网友名单。当你和你的OICQ伙伴进行聊天时,如果你和对方的连接比较稳定,你和他的聊天内容都是以UDP的形式,在计算机之间传送。如果你和对方的连接不是很稳定,QQ服务器将为你们的聊天内容进行“中转”。其他的即时通信软件原理与此大同小异。
OICQ的通讯原理:
1.用户首先从QQ服务器上获取好友列表,以建立点对点的联系。
2.用户( Clientl)和好友(Client2)之间采用UDP方式发送信息。
3.如果无法直接点对点联系,则用服务器中转的方式完成。我们看到两个OICQ用户如果是在两个不同的内网上,它们经过登录后可以不同过服务器来直接通讯。那这是为什么呢。其根本原因是OICQ使用了UDP协议,这样用户之间的通讯自己完成就减少了服务器的负担。那么到底原理是什么样的,为什么TCP应用就不能达到这一要求。这就涉及到NAT ( Network AddressTranslator)技术。NAT技术使得一个私有网络可以通过internet注册IP连接到外部世界,位于inside网络和outside网络中的NAT路由器在发送数据包之前,负责把内部IP翻译成外部合法地址。内部网络的主机不可能同时与外部网络通信,所以只有一部分内部地址需要翻译。"NAT"的翻译可以采取静态翻译和动态翻译两种。静态翻译将内部地址和外部地址一对一对应。当使用了动态翻译时就采用port multiplexing技术,通过改变外出数据的源port技术可以将多个内部IP地址影射到同一个外部地址,这就是PAT (port address translator)。在这种情况下,一个TCP连接只能和固定的连接方通讯,而UDP应用本身就可以接受不同数据来源的数据包,所以在NAT转换的时候能够完成两个客户端之间的通讯,从而达到了客户端直接通讯的目的。
总的来说,OICQ的应用在客户端方面符合即时通讯系统的模型。客户端之间的通讯中,采用了UDP的通讯方式,当客户端之间无法直接通讯时,采用通过服务器转发的方式来实现即时信息的传送。
2.2所用技术
JAVA多线程技术:多线程的各个线程看上去像是并行地独自完成各自的工作,就像一台一台计算机上运行着多个处理机一样。在多处理机计算机上实现多线程时,它们确实可以并行工作,而且采用适当的分时策略可以大大提高程序运行的效率。而作为接受客户端请求的服务器来说,必须使用多线程技术来接受不同时刻的请求,接收一个处理一个,将其放入线程队列,然后继续监听其他的请求。
网络通讯与Socket编程:java网络编程中有两种不同的通讯协议,分别是TCP(面向连接)与UDP(面向无连接),两种协议各有优缺点。
TCP:是Tranfer Control Protocol的简称,是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。
UDP:是User Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。
JDBC数据库技术:JDBC, 全称为Java DataBase Connectivity standard, 它是一个面向对象的应用程序接口(API), 通过它可访问各类关系数据库。JDBC也是java核心类库的一部分。JDBC的最大特点是它独立于具体的关系数据库。与ODBC (Open Database Connectivity)类似, JDBC API 中定义了一些Java类分别用来表示与数据库的连接(connections), SQL语句(SQL statements), 结果集(result sets)以及其它的数据库对象, 使得Java程序能方便地与数据库交互并处理所得的结果。使用JDBC, 所有Java程序(包括Java applications , applets和servlet)都能通过SQL语句或存储在数据库中的过程(stored procedures)来存取数据库。
SWING界面设计:java的扩展包,其中包括众多的控件以及丰富的控件操作功能,使用户可以简单的利用它画出应用程序的界面,结合JBuilder9.0带的绝对定位类包,可以设计出非常好看的用户界面。
JSP与SERVLET技术:JSP和SERVLET是在j2ee平台下开发WEB应用的基础, JSP是由SUN公司倡导 众多公司参与一起建立的一个动态网页标准技术,JSP技术为建立具有动态生成内容的WEB应用提供了一种简便而且功能强大的途径,它可以快速开发出与平台无关的基于WEB的应用,JSP是更高级的SERVLET,在运行的时候JSP先被转化为SERVLET。
UML:UML是一个统一建模语言, 是当今世界上面向对象系统开发领域中的工具之一,它是一种可视化的建模语言,能够让系统构造者用标准的、易于理解的方式建立起能够表达出他们想像力的系统蓝图,并且提供了便于不同的人之间有效地共享和交流设计结果的机制。它包含了9种图形还有其他一些特征,很方便用户进行建模。
2.3工具及开发平台
Borland JBuilder是全球第一的跨平台Java开发环境,可以用于构建符合工业标准的Java应用系统,不仅可以开发桌面级程序,并且可以开发EJB、Web、XML以及数据库等各类应用程序。双向、可视化设计工具使得我们可以快速的构建各种应用程序,并部署至多种应用程序服务器,利用JBuilder,我们可以快速、方便的构建出Java应用程序,并且其中提供了一个类似于VS.NET中的界面编辑器功能,它具有绝对的定位功能,我们不用再手工粗糙的排列JAVA的LayoutManager,这一切完全可以用JBuilder开快速完成。
Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括 Java 开发工具(Java Development Tools,JDT)。 虽然大多数用户很乐于将 Eclipse 当作 Java IDE 来使用,但 Eclipse 的目标不仅限于此。Eclipse 还包括插件开发环境(Plug-in Development Environment,PDE),这个组件主要针对希望扩展 Eclipse 的软件开发人员,因为它允许他们构建与 Eclipse 环境无缝集成的工具。更舒服的是,利用Eclipse中的MyEclipse插件来搭建一个动态JSP程序,快速,简单、方便。
Rose一套非常有使用价值的系统建模工具,其中提供了非常方便的系统建模功能,比如用例图、行为图、活动图、时序图等。利用它可以加快系统设计开发效率,同时可以给用户和开发者提供清晰的图,使他们之间的交流变得更加的方便有效。
SQL SERVER2000数据库是微软的功能强大的数据库管理系统,具备很多数据库管理常用的功能,例如存储过程、数据查询与更新等,是一个非常理想的后台数据库系统。
Tomcat是Sun的JSWDK(JavaServer Web Development Kit)中Servlet的运行环境(servlet容器), 是一个免费的开源的Serlvet容器,它是Apache基金会的Jakarta项目中的一个核心项目,由Apache,Sun和其它一些公司及个人共同开发而成。
2.4 系统配置要求
推荐配置如下:CPU2G以上, 内存512以上,运行平台基于Windows平台。 客户端需要安装java虚拟机,同时还要有JICQ的客户端程序。服务器端需要安装Sql server2000数据库, 服务器端如果是windowsXP系统要打上Sql server 2000的SP3或者SP4补丁包,同时服务器端需要安装Web服务器TOMCAT,还有JICQ的服务器端程序。
3系统体系结构的设计
3.1 需求描述
伴随着当今互联网的迅速发展,人们之间的信息交互的实时性能变得越来越重要,传统的电子邮件交互已经不能够满足人们的即时通讯要求,鉴于此种情况打算开发出一款类似于腾讯QQ的即时通讯软件,只要经过注册你便可以获取一个帐号,通过该帐号你可以在客户端登陆,成功登录后便可以在互联网上与你的亲朋好友进行畅谈,由于技术和时间问题,该软件主要提供私聊、群聊、好友管理、群管理等常用功能,其它一些功能比如文件传输、语音聊天和视频聊天等功能,由于技术问题暂时没有实现,可以在该系统的基础上实现这些功能,也可以在此基础上进行更多功能的扩展。
3.2系统架构设计
该系统主要包括三层,客户端,服务器端,以及数据库服务器,客户端用来提供用户的登录,服务器端用来对登录的用户进行管理以及用来处理信息之间的转发,数据库服务器主要存放一些重要的信息。它们之间的关系如下图所示:
图1 三层模型
中间层又分成四个部分:
图2 中间层的构成
本系统采用的设计模型为平时所说的C/S架构,Client/Server,系统总体模型图如下:
图3 客户端/服务器端模型图
3.3 系统的总体功能设计
3.3.1总体功能设计
根据上述需求的描述,对该系统按照功能进行了模块的细化,主要包括注册登录、好友聊天、好友组管理、群聊天4个模块,还有很多其它小模块,这4个模块是实现该系统的核心模块,模块之间的耦合程度非常低,其中注册模块是通过B/S结构来实现,不需要安装客户端。下图是上述的4个重要模块的用例交互图。
图4 总功能用例图
3.3.2注册模块设计
注册模块是整个系统的最基础模块,该模块主要通过B/S模式来实现,技术上采用J2EE的三(N)层结构,它有以下特点:
1.能有效降低建设和维护成本,简化管理;
2.适应大规模和复杂的应用需求;
3.可适应不断的变化和新的业务需求:
4.访问异构数据库;
5.能有效提高系统并发处理能力;
6.能有效提高系统安全性
该模块表现层主要用的技术是Jsp和servlet,后台数据库用的是Sql 2000数据库。该模块主要包括以下功能:帐号注册、密码的找回、密码的修改以及个人信息的查询。通过该模块,用户可以与Web服务器交互进行号码的注册、密码找回等功能。下图是一张简单的J2EE的结构图,该系统只是用到了其中的一部分技术。
图5 J2EE结构图
下边是用户注册与Web服务器之间的用例交互图。
图6 注册用例交互图
下边是用户注册的活动图。
图7 用户注册活动图
3.3.3 登录模块设计
该模块主要给注册成功的用户提供一个登录界面,用户根据自己注册的帐号信息可以与服务器交互,如果提供的信息通过服务器的验证便可以成功的登录系统,成功登录系统之后,可以进行一些操作,比如和好友聊天等,使用该模块之前必须安装一个客户端。登录模块只是一个简单的页面,主要填写用户名、密码之类的信息,登录成功后的主界面包含了系统的大部分功能,比如添加和删除好友、添加和删除好友分组、和朋友聊天等功能。下图是登录模块的用例图。
图8 登录用例图
下边的登录模块的活动图,主要是对用户提供的用户名和密码提供验证。
图9 登录活动图
下边是用户之间交互信息的时序图,主要包括从用户登录到通过验证然后进行信息的发送,给好友发送信息包含两种情况,第一,如果好友在线的话消息直接通过服务器中转发送给好友,如果对应的好友不在线,则讲发送的信息保存到数据库中,当该好友上线的时候从数据库中读出相应的信息进行发送。
图10 用户信息交互图
3.3.4用户间交互模块设计
该模块主要实现已用户之间的信息交流,用户交流的前提是先要添加好友,可以通过查找功能进行好友的查找,找到要添加的好友后,通过发送好友申请消息来添加好友,当对方通过添加好友的验证消息后,便可以成功的添加好友。只有成功的添加好友之后,才可以进行用户之间的信息的相互交互。下边是用户交互的用例图。
图11 用户交互用例图
用户之间聊天的信息主要通过聊天服务器进行中转,用户之间聊天内容主要存储在客户端的一些文件中,可以通过查看聊天功能来进行对这些聊天信息的读取。下图是用户交互的活动图:
图12 用户交互活动图
下边是好友添加的时序图
图13 好友添加时序图
3.4数据库设计
3.4.1数据库物理模型
通过对系统需求的分析,在关系数据库中建立相应的表,并建立了表之间的相互关系,下边的图是在Sql 2000下这些表之间的对应关系图。
图14 数据库物理模型
3.4.2数据字典
下边是关系数据库中每个表所对应的字段的详细信息
表1 JUSERS(用户表)用来存放用户注册时的基本信息
简称 | 字段名 | 类型 | 长度 | 允许空 | 备注 |
JICQ | 号码 | bigint | 8 | Not null | PK |
JPassWord | 密码 | varchar | 50 | Not null | |
JShowName | 昵称 | varchar | 100 | Not null | |
JTrueName | 真实名称 | varchar | 100 | ||
JAge | 年龄 | Int | 4 | ||
JSex | 性别 | char | 4 | ||
JCountry | 国家 | varchar | 50 | ||
JProvince | 省 | varchar | 50 | ||
JCity | 市 | varchar | 50 | ||
JStatus | 状态 | smallint | 2 | Not null | |
JUserIP | IP | varchar | 50 | Not null | |
JPicID | 图片ID | int | 4 | Not null | |
JICQShowID | int | 4 | |||
JEmail | 电子邮件 | varchar | 100 | ||
JUnderWrite | 个人签名 | varchar | 500 | ||
JProfession | 专业 | varchar | 50 | ||
JStar | 星座 | varchar | 50 | ||
JXuexing | 血型 | varchar | 50 | ||
JGradute | 学历 | varchar | 50 | ||
JAddress | 住址 | varchar | 200 | ||
JPostalcode | 邮编 | char | 6 | ||
JPersonalPage | 个人主页 | varchar | 500 | ||
JOption | 个人爱好 | Int | 4 | ||
JIDCardType | 证件类型 | char | 20 | ||
JUserMoblie | 手机号码 | varchar | 11 | ||
JUserIDCard | 用户卡号 | varchar | 30 | ||
JProtectPwdQuestion | 密保提问 | varchar | 50 | ||
JProtectPwdAnswer | 密保答案 | varchar | 50 |
表2 Jmessages(消息表)用来存放用户发送的离线消息
简称 | 字段名 | 类型 | 长度 | 允许空 | 备注 |
MessageID | 自增主键 | bigint | 8 | Not null | |
MyJICQ | 自己号 | bigint | 8 | Not null | |
FriendJICQ | 朋友号 | Bigint | 8 | Not null | |
MessageHead | 消息标题 | Varchar | 200 | Not null | |
flag | 消息状态 | smallint | |||
MessageContent | 消息内容 | varchar | 500 | Not null |
表3 JFriends(朋友表)用来存放用户的好友信息
简称 | 字段名 | 类型 | 长度 | 允许空 | 备注 |
JICQ_Friend_ID | 自增主键 | bigint | 8 | Not null | PK |
JICQ | 自己icq号 | bigint | 8 | Not null | |
JFriendID | 朋友icq号 | bigint | 8 | Not null | |
JFriendTypeID | 朋友类别 | int | 4 | Not null | FK |
表4 JFriendType(朋友类别表)用来存放用户的好友组信息
简称 | 字段名 | 类型 | 长度 | 允许空 | 备注 |
JFriendTypeID | 主键自增 | int | 4 | Not null | PK |
JFriendTypeName | 好友组名称 | varchar | 100 | Not null | |
JICQ | Icq号码 | bigint | 8 | Not null |
表5 JGroups(用户组表)用来存放用户的群组信息
简称 | 字段名 | 类型 | 长度 | 允许空 | 备注 |
JGroupID | 群号码 | int | 4 | Not null | PK |
JGroupJICQ | 群名称 | bigint | 8 | ||
JGroupName | 群名称 | varchar | 100 | Not null | |
JGroupPicID | 群图片ID | int | 4 | Not null | |
JGroupType | 群类别 | varchar | 100 | ||
JGroupBcast | 群公告 | varchar | 500 | ||
JGroupInfo | 群信息 | varchar | 500 |
表6 JGroup_Users(用户和组关联表)用户和组之间的关联表
简称 | 字段名 | 类型 | 长度 | 允许空 | 备注 |
JGroupID_JICQ | 主键 | bigint | 8 | Not null | PK |
JGroupID | 组ID | Int | 4 | Not null | FK |
JICQ | Icq号码 | bigint | 8 | Not null | FK |
JGroupName | 群名称 | varchar | 200 | Not null | |
JMessageStatus | 群消息状态 | smallint | 2 | Not null |
4系统实现
4.1网络通讯编码实现
4.1.1聊天客户端部分代码
下边是聊天客户端的核心代码,它用来判定消息的来源以及针对该消息所进行的相应的操作。
for(int i=0;i<MyPersonTree.alist.size();i++) //判断是哪个好友发来的信息
{
p=(Person)MyPersonTree.alist.get(i);
if(p.getID().equals(hisJICQ))
break;
else p=null;
}
if(p!=null) //队列中有该好友
{
JICQChatFrame jchatExist=null;
int isExistFrame=0;//判定聊天窗口是否已经打开
for(int i=0;i<MyPersonTree.vector.size();i++) //遍历向量
{
jchatExist=(JICQChatFrame)MyPersonTree.vector.get(i);
if(jchatExist.JICQ.equals(hisJICQ))
{
isExistFrame=1;//聊天窗口已经打开
break;
}
}
if(isExistFrame==0)//聊天窗口没有打开,新建一个窗口
{
JICQChatFrame jchat=new JICQChatFrame(p,this);
MyPersonTree.vector.addElement(jchat);
jchat.setMessage(headmsg,msg);
}
else
{//在聊天窗口中显示该信息
jchatExist.setMessage(headmsg,msg);
}} else
{
JICQChatFrame jchatExist=null;
int isExistFrame=0;
for(int i=0;i<MyPersonTree.UnKonwVector.size();i++) //陌生人的信息
{
jchatExist=(JICQChatFrame)MyPersonTree.UnKonwVector.get(i);
if (jchatExist.JICQ.equals(hisJICQ))
{
isExistFrame=1;
break;
}
}
}
4.1.2服务器端监听与转发消息代码
下边是服务器端的监听程序,如果发现有socket连接,就创建一个与该连接所对应的一个线程,该线程主要用来处理用户之间的信息交互。
public void run()
{
try
{
while(true) //始终监听状态
{
Socket client=listen.accept();
//创建用户线程
PersonThread f=new PersonThread(client);
f.setPriority(Thread.MIN_PRIORITY);
f.start();
}
}
Catch(IOException e)
{
System.err.println("Erro:"+e);
System.exit(1);
}
}
//服务器端的消息转发函数
public static void broadcast(String msg,String hisJICQ)
{
int i;
PersonThread you;
for(i=0;i<connections.size();i++)
{
you=(PersonThread)chatserverthree.connections.elementAt(i);
if(you.JICQ.equals(hisJICQ))
you.send(msg);
}
}
4.1.3服务端单线程上线处理代码
下边是服务器端上的单线程的处理代码,主要通过网络流来读取客户端发送的消息,然后将消息分解,用来区分消息的类型,譬如是群消息还是个人消息等。
While(true)
{
line=in.readUTF(); System.out.println(line);
//将读取的信息按照特定格式进行拆分
StringTokenizer stk=new StringTokenizer(line,"#"); //PEOPLE+"#"+JICQ
if(stk.hasMoreElements()) key=(String)stk.nextElement();
//用户上线提示
if(key.equals("PEOPLE"))
{
try{ String JNUM=(String)stk.nextElement();
this.JICQ=JNUM;
for(int i=0;i<chatserverthree.connections.size();i++)
{PersonThread tt=(PersonThread)chatserverthree.connections.get(i); if(tt.JICQ.equals(this.JICQ))
{
chatserverthree.broadcast("RELOG#YES",tt.JICQ);
chatserverthree.connections.remove(i);
tt.stopThread();
break;
}}
//将该线程加入到线程向量中
chatserverthree.connections.addElement(this);
Friends f=new Friends();
ResultSet rs=f.selectAddMePerson(JNUM);
ArrayList flist=new ArrayList(50);
while(rs.next())
{
flist.add(rs.getString(1));
}
for(int i=0; i<chatserverthree.connections.size();i++)
{
PersonThread pt=(PersonThread)(chatserverthree.connections.elementAt(i));
if(flist.contains((String)pt.JICQ))
{
chatserverthree.broadcast(line,pt.JICQ);
}}
s_MyDetails sMy=new s_MyDetails();
//从信息表中读取离线信息,然后将之删除
ResultSet rsMessage=sMy.isHaveMessage(JNUM);
if(rsMessage!=null)
while(rsMessage.next())
{
int FriendJICQ=rsMessage.getInt("FriendJICQ");
int MyJICQ=rsMessage.getInt("MyJICQ");
String msgHead=rsMessage.getString("MessageHead");
String msgBody=rsMessage.getString("MessageContent");
int flag=rsMessage.getInt("flag");
String Allmsg="";
if(flag==1)
Allmsg="MSGONE#"+FriendJICQ+"#"+MyJICQ+"#"+msgHead+"#"+msgBody; else Allmsg="ADDFRIEND#"+FriendJICQ+"#"+MyJICQ+"#"+msgHead+"#"+msgBody;
chatserverthree.broadcast(Allmsg,JNUM);
} sMy.delOldMessage(JNUM); } }
4.2 系统运行的效果图
4.2.1 登录界面
该界面提供用户输入自己注册号码和相应的密码,然后登录系统,如果还没有注册帐号,可以点“申请”进行帐号的申请。如下图所示:
图15 登录界面
4.2.2 主界面
登录成功后的主界面,主要是一些好友的信息,以及一些好友分组的信息,在此界面上可以进行好友的添加、查找、删除,以及好友组的添加、删除,同时还可以查看最近联系人等功能。
图16 主界面
4.2.3 群聊天界面
如果你已经成功的加入该群,你就可以在群中和其他群成员进行一些信息的交互。
图17 群聊天界面
4.2.4 好友聊天界面
该界面主要是用户聊天的主要界面,主要提供了发送和接受聊天信息功能,以及查看聊天记录,同时还可以查看好友的一些基本信息。
图18 好友聊天界面
4.2.5 好友查找界面
好友添加和查找的界面,你可以根据不同的条件来进行好友查找的筛选,比如只查找在线的用户或者可以查看所有用户,还可以根据一些信息讲查找范围缩小,比如根据用户的性别 年龄等信息进行查询,以满足自己的查找需要。
图19 添加好友界面
4.3注册模块的实现
4.3.1 数据库连接
JDBC数据库连接的核心代码,IP地址设定为本机的IP:
Connection conn = null;
Statement st = null;
try {
//加载驱动程序
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
//创建数据库的连接
Conn=DriverManager.getConnection("jdbc:sqlserver://127.0.0.1;databaseName=JICQ","sa", "sa");
}
4.3.2 字符编码过滤器的核心代码
该过滤器实现Servlet的过滤器接口,设置字符编码为GB2312,主要用来解决在表单提交工程中所出现的中文乱码问题,主要用来解决以post方式提交的表单所出现的中文乱码问题。
public class CharacterEncodingFilter implements Filter
{
protected FilterConfig filterConfig;
protected String encoding=null;
protected boolean ignore=true;
//初始化字符过滤器
public void init(FilterConfig filterconfig)
throws ServletException
{
this.filterConfig = filterconfig;
//设定编码方式,从web.xml配置文件中获取该参数
this.encoding = filterconfig.getInitParameter("encoding");
String value = filterconfig.getInitParameter("ignore");
if(value==null)this.ignore=true;
else if(value.equalsIgnoreCase("true"))this.ignore=true;
else if(value.equalsIgnoreCase("yes"))this.ignore=true;
else this.ignore=false;
}
//重写Filter的过滤方法
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
if(ignore||request.getCharacterEncoding()==null){
String encoding =this.selectEncoding(request);
if(encoding!=null){
System.out.println("encoding"+encoding);
request.setCharacterEncoding(encoding);
}
}
chain.doFilter(request,response);
}
//销毁该字符过滤器
public void destroy()
{
this.encoding=null;
this.filterConfig=null;
}
protected String selectEncoding(ServletRequest servletrequest)
{
return (this.encoding);
}
}
4.4 注册模块运行效果图
4.4.1 主页面
以下的主页面,在该页面你可以注册新的帐号、密码的找回等功能。
图20 注册模块主页面
4.4.2 注册页面
主要是进行一些用户注册基本信息的填写。
图21 注册页面
5 系统测试与运行
在系统的开发过程中,遇到了很多的技术难点。
难点之一,在注册模块遇到数据库连接不成功的问题,通过请教老师,成功解决问题。原因是如果是在windows平台下用JDBC连接数据库,就会出现这种情况。解决的方法是下载sql server2000的sp3补丁包,如果没有打该补丁包,就会出现连接数据库不成公的问题。
难点之二,Tomcat下的中文乱码的解决方案,乱码问题是由于java语言的编码问题所造成的。
问题描述,表单提交时可以采用post和get两种方式,tomcat对这两种提交方式采取了不同的处理方式,对post方式可以采用过滤器来实现,上边已经介绍过了。
而对get方式提交的表单,过滤器不起作用,要修改tomcat下边的一个配置文件,具体文件是conf目录下边的server.xml这个配置文件,找到对8080端口进行服务的Connector组件的设置部分,给该部分添加一个属性:URLEncoding=”GBK”.修改后的Connector组件设置如下:
<Connector port="8080"maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000
disableUploadTimeout="true" URIEncoding="gb2312"/>
下边是系统打包、部署与运行图
图 22 系统部署图
结 论
通过老师的指点和自己的努力,顺利地完成了该系统。伴随着当今互联网的迅速发展,网上通讯已经成为很多人的的一种交流方式,该系统的设计就是为了实现互联网上的即时通讯,它是利用当今最为流行的java编程语言来实现的即时通讯工具的雏形,其中涉及的很多方面都是java常用的技术或者难点。你可以通过该系统进行号码的申请,申请号码之后,你可以登录系统进行一些简单的操作和设置,比如添加好友以及好友分组等,然后你可以和好友进行交流以及,譬如即时发送、即时回复等。该系统可以运行在互联网或者局域网上,使用户可以很方便的进行信息的交流。
通过本系统的实现,发现即时通讯具有很好的应用前景,而且功能会越来越完善,服务商所提供的服务也会越来越多,用户也越来越多,即时通讯软件本身的种类也在不断扩充,就一种即时通讯软件来讲也在不断的升级完善中。即时通讯的发展速度和应用可以说是Internet乃至整个世界的一个奇迹,我真诚的希望能有更多的科学工作者和专家加入到这一领域的研究中来。
参考文献
[1] 冯博,应群.面向对象的JAVA网络编程[M].北京:清华大学出版社, 2003。
[2] Bruce Eckel[美].java编程思想[M].陈昊鹏译.北京:机械工业出版社,2003。
[3] 特罗特[美].设计模式解析[M].徐言声译.北京:人民邮电出版社,2004。
[4] 王少峰.面向对象技术UML教程[M].北京:清华大学出版社,2005。
[5] 结城浩[日].java多线程设计模式[M].博硕文化译北京:中国铁道出版社,2003。
[6] 核心研究室.深入浅出Java Swing程序设计[M].北京:中国铁道出版社,2005。
[7] Dreamtech软件研发组[美]. 即时消息传递系统源代码解析[M].李军译.北京, 电子工业出版社, 2001。
[8] 哈罗德[美].java网络编程[M].刘东华译.北京:中国电力出版社,2000。
[9] Joseph Schmuller[美].UML基础案例与应用[M].李虎等译著.北京:人民邮电出版社,2002。
[10] 张洪伟.Tomcat Web开发及整合应用[M].北京:清华大学出版社,2006。
致 谢
本文是在何林波老师的热情关心和指导下完成的,他渊博的知识和严谨的治学作风使我受益匪浅,对顺利完成本课题起到了极大的作用。在此向他表示我最衷心的感谢!
感谢网友”拥抱开源”在课题研究过程中所给予的帮助!在论文完成过程中,本人还得到了其他老师和许多同学的热心帮助,本人向他们表示深深的谢意!
最后向在百忙之中评审本文的各位专家、老师表示衷心的感谢!
关注博主下篇更精彩
一键三连!!!
一键三连!!!
一键三连!!!
感谢一键三连!!!