获取项目源文件,技术交流与指导联系Q:1225467431
摘 要
计算机网络的迅速发展,对人类社会诸多领域产生了巨大的影响。尤其是,随着信息时代的来临,人们之间愈来愈趋向于通过网络来交流和传递信息。而聊天系统正是当前人们使用最多的中介。在这个平台上,许多认识或不认识的人们彼此间能够随意的相互交流。因此,开发和架构这种平台符合时代发展的需要。
本系统在开发中用到了局域网通信机制的原理,通过直接继承Thread类来建立多线程。开发中利用了计算机网络编程的基本理论知识CP/IP协议、客户端/服务器端模式(Client/Server模式)、网络编程的设计方法等。在网络编程中对信息的读取、发送,是利用流来实现信息的交换,其中介绍了对实现一个系统的信息流的分析,包含了一些基本的软件工程的方法。
关键字: Socket;服务器端; 客户端; 连接(connection)
目 录
摘 要 I
引 言 1
1系统分析 2
1.1可行性分析 2
1.2需求分析 2
1.2.1功能分析 2
1.2.2性能分析 4
1.2.3用例图 5
1.2.4时序图 6
1.2.5活动图 7
2 总体设计 12
2.1功能模块图 12
2.2数据库设计 13
2.2.1 E-R图 13
2.2.2表结构设计 16
2.3类图 20
3 详细设计及实现 22
3.1界面设计 22
3.2数据输入输出设计 27
3.2.1数据输入 27
3.2.2数据输出 27
3.3代码实现 27
3.3.1服务器端设计 27
3.3.2传递包的设计 31
3.3.3聊天客户端设计 32
3.3.4文件传输设计 34
4 系统测试 36
4.1注册测试 36
4.2登陆测试 36
4.3私聊测试 37
4.4群聊测试 38
4.5文件传输测试 39
结 论 41
致 谢 43
参 考 文 献 44
引 言
当今主流的聊天工具有QQ,ICQ,MSN Messenger,Yahoo Messenger等,国内最热门的当属QQ,腾讯QQ(OICQ)是由深圳市腾讯计算机系统公司开发的,基于Internet的即时寻呼软件。您可以使用QQ和好友用户进行交流,信息即时发送,即时回复,收发及时、功能全面。此外QQ还具有BP机网上寻呼、聊天室、传输文件、语音邮件、手机短讯服务等功能,QQ不仅仅是虚拟的网络寻呼机,更可与传统的无线寻呼网、GSM移动电话的短消息系统互联,目前QQ和全国多家寻呼台、移动通信公司有业务合作。是国内不可多得的中文网络寻呼机。QQ支持显示朋友在线信息、即时传送信息、即时交谈、即时发送文件和网址。QQ可以在Win95/98/NT/2000操作系统下运行,是十分灵活的网络寻呼工具。它会自动检查您是否已联网,如果您的电脑已连入Internet,可以搜索网友、显示在线网友,可以根据QQ号、昵称、姓名、email地址等关键词来查找,找到后可加入到通讯录中。当您的通讯录中的网友在线时,QQ中朋友的头像就会显示在线,根据提示就可以发送信息,如果对方登记了寻呼机或开通了GSM手机短消息,即使离线了,您也可及时将信息传递给您的好友。
虽然以上这些软件是免费的,并且功能越来越强大。但是它们的唯一的不足就是必须要联网或者下载到它们的服务端,要不然是没法脱离Intenet使用的。为了能在一个没有连接到Intenet的局域网使用聊天工具,那就必须要有服务器端。
本系统就是包括服务器端与客户端,可以在局域网聊天的一个工具。
1 系统分析
1.1可行性分析
1)经济可行性:本系统需要一个oracle数据库服务器,由于使用人数比较少,安装一个免费的oracle数据库完全可以应付需要,所以成本就不用考虑了。
2)操作可行性:只要一台以上计算机连接在同一个局域网内,本系统就可以安装使用,所以操作上完全不存在问题。
3)技术可行性:本系统采用Java语言,是基于CS架构的。开发这个系统需要开发者对socket编程和java Swing这两方面的技术比较熟。由于本人长期从事于java语言编程,所以技术方面是可行的。
1.2需求分析
1.2.1功能分析
本系统要实现的功能如下:
1)注册
服务器收到用户的注册请求,便开始接受客户传递的信息,诸如客户的呢称,性别,籍贯,个人资料等,接受完毕后,便通过Jdbc-Odbc与后台数据库连接,然后向数据库添加记录,如果成功,便向客户返回其号码。客户收到服务器返回的信息后,便打开主登陆窗口。
2)登陆
在客户端,用户输入其号码和密码,然后建立与服务器的连接,告诉服务器我要登录,服务器收到后,开始通过JdbcOdbc读取数据库,然后与用户输入的信息比较,如果成功,便打开主程序窗口。然后客户向服务器请求读取好友名单,服务器收到该请求,开始读取数据库中的表,得到好友的号码后,再在icq表中读取好友资料,然后向客户端发送这些信息,客户收到后就在主窗口显示好友,并且建立几个矢量(Vector)用以存储好友的呢称,号码。
3)私聊
私聊就是两个聊天。客户端首先发送消息到服务器端,服务器端根据发送人信息和接收者信息来转发。例如服务器接收到一个A发给B的消息先判断B是否已经在线,如果在线就将信息发送过去。B接收到A发来的信息,如果是未建立对话窗口,就询问是否建立对话,否则就丢弃信息。
4)群聊
群聊,就是多人一起聊天。过程与私聊差不多。唯一的不同就是服务器会将信息转发给指定群的所有成员。
5)创建分组
用户注册以后默认的好友分组只有一个。用户在执行添加分组操作以后,客户端分将一个这个动作的信息发送给服务器端(主要是FromClientlisten)。服务器端的fromClientListen接收到这个请求,会进行数据库操作,将要添加的分组信息插入到数据库中。如果成功,则返回这个分组的信息给客户端,否则返回错误提示信息。
6)创建群
用户注册以后群个数为0。用户在执行添加群操作以后,客户端分将一个这个动作的信息发送给服务器端(主要是FromClientlisten)。服务器端的fromClientListen接收到这个请求,会进行数据库操作,将要添加的群信息插入到数据库中。如果成功,则返回这个群的信息给客户端,否则返回错误提示信息。
7)查找好友并加为好友
输入要查找的用户ID号,客户端发送一个查询信息给服务器端,如果找到就返回用户服务信息。打开一个用户信息显示界面,该界面会提供一个“添加为好友”按钮,点击后可将此人加为好友。如果未找到,弹出一个信息提示框。
8)查找群并加入群
输入要查找的群ID号,客户端发送一个查询信息给服务器端,如果找到就返回用户服务信息。打开一个群信息显示界面,该界面会提供一个“加入此群”按钮,点击后可将此人加为好友。如果未找到,则弹出一个信息提示框。
9)文件共享
在启动文件传输服务器的共享文件功能之前,要设置它的IP号和端口,如果设置不好。好友将无法下看到这些共享的文件。还有一个重要的步骤就是添加共享文件或目录。最后启动文件共享。
10)下载文件
使用文件传输的客户端要正确配置好服务器的IP和端口号,以及下载好的文件的存放目录。如果其中之一配置不好,文件下载将会失败。设置好以后,点击“连接”按钮,如果配置正确,这时将会看到服务器共享的文件。目前不能支持文件夹下载,当看到一个文件夹以后,可以双击该文件夹并查看文件夹里面的文件。
1.2.2性能分析
本系统由于采用免费的oracle数据库软件,连接数最多不能超过200,所以并发访问数据库的人数不能超过200人。
1.2.3用例图
图2.1 系统用例图
1.2.4时序图
客户登陆、注册时的服务器端时序图
图2.2 注册、登陆时的服务端的时序图
本图说明:
服务器接每次与一个客户连接以后,就会去创建一个监听线程。通过线程来接收客户端发送的所有数据。如果要查询数据库,监听线程会请求获得一个数据库连接.如果数据库连接已经获得,就把连接交给DBOperation对象,通过此对象可以返回给监听线程必要的结果。最后监听线程会通过Socket将结果返回给客户端。
1.2.5活动图
1)用户登陆活动图
图2.3 用户登陆活动图
本图说明:首先填写登陆信息,提交以后服务器会对用户名和密码进行验证。如果不正确,返回一个提示信息。如果登陆成功,就更新在线状态。通知所有好友自己已经上线。
2)客户之间的通信活动图
图2.4 客户通信活动图
本图说明: 短消息发送以后,服务器端对应的监听线程会接收到一个数据包。此包中包含接收者的信息,如果接收者在线,数据包将会转发到接收者。如果不在线,就写入数据库。
3)客户之间的文件传送活动图
本图说明:客户端向服务器发送文件下载请求。如果服务器端同意下载,就读取文件流并将数据流写入到客户端。客户端读取到文件名之后,立刻创建一个新的文件并将读取的数据写入到文件中。
图2.5 文件传送活动图
4)新增好友活动图
根据好友ID号查找好友,如果此ID存在,就将用户信息发送到客户端。同时将好友关系写入到数据库。
图2.6 新增好友活动图
5)删除好友活动图
此图说明:客户向服务器发送删除好友请求。服务器接收到删除好友请求以后,将好友关系从数据库中删除。
图2.7 删除好友活动图
2 总体设计
2.1功能模块图
本系统主要由由两个子系统组成:1)文件传输系统;2)聊天子系统。
文件传输系统的功能主要有:1)共享文件;2)查看并下载文件。
聊天子系统的功能有:1)注册;2)登陆;3)添加群;4)查找群
5)私聊;6)群聊;7)查看好友资料;8)查找好友;9)添加好友;
10)创建好友分组。
图3.1 系统功能模块图
2.2数据库设计
2.2.1 E-R图
图3.2 系统E-R图
用户表(QQUser):
属性:id,account(登陆账号),pwd,nickname,sign(个性签名),sex,email,head(头像)
关系:
一个用户可以有多个好友分组。
一个用户可以有多个群。
一个用户可以有多条留言。
好友分组表(Qqperson_group):
属性:id,userid(创建者ID),name(分组名)
关系:一条记录只对应一个用户,但是可以拥有多个组成员。
群表(Qqpublic_group):
属性:id,userid(创建者ID号),name(群名),sign(群公告)
关系:一个群只有一个创建者,但是可以拥有多个群成员。
图3.3 系统各表之间的联系图
2.2.2表结构设计
表3.1 客户信息表(qquser)
1 |
自动id号 |
Id |
整数 |
2 |
用户账号 |
Account |
整数 |
3 |
用户密码 |
Pwd |
字符 |
4 |
用户昵称 |
Nickname |
字符 |
5 |
用户签名 |
sign |
字符 |
6 |
用户性别 |
Sex |
字符 |
7 |
用户邮箱 |
|
字符 |
8 |
用户头像 |
Head |
字符 |
表3.2 Qq消息表(QQMessage)
1 |
自动ID |
ID |
整数 |
2 |
发信人 |
Account_from |
整数 |
3 |
收信人 |
Account_to |
整数 |
4 |
发送内容 |
Content |
字符 |
表3.3 用户分组表(qqpersongroup)
1 |
自动ID |
ID |
整数 |
2 |
拥有者Id |
userid |
整数 |
3 |
分组名称 |
name |
字符 |
表3.4 公共群表(qqpublic_group)
1 |
自动ID |
ID |
整数 |
2 |
创建人 |
userid |
整数 |
3 |
群名称 |
name |
整数 |
4 |
群的公共消息 |
sign |
字符 |
表3.5 用户与群的中间表(qquser_publicgroup)
1 |
自动ID |
ID |
整数 |
2 |
加入的群ID |
groupid |
整数 |
3 |
加入的用户的ID |
userid |
整数 |
表3.6 用户与分组的中间表(QQuser_persongroup)
1 |
自动ID |
ID |
整数 |
2 |
加入的分组的id |
groupid |
整数 |
3 |
加入分组的用户的id |
userid |
整数 |
以上各表创建的代码如下:
1)创建用户表
create table qquser(
number primary key,
account number unique,
nickname varchar(100),
sign varchar(500),
sex varchar(10),
email varchar(100),
head varchar(200));
2)创建分组表
create table qqperson_Group(
id number primary key,
userid references qquser(id),
name varchar(100));
3)创建群表
create table qqpublic_group(
id number primary key,
userid number references qquser(id),
name varchar(100),
sign varchar(800));
4)创建消息表
create table qqmessage(
id number primary key,
account_from number,
account_to number,
content varchar(1000));
5)创建用户与群的中间表
create qquser_publicgroup (
id number primary key,
groupid number references qqpublic_group(id) ,
userid references qquser(id););
6)创建用户与分组的中间表
create qquser_persongroup(
id number primary key,
groupid number references qqpublic_group(id) ,
userid references qquser(id));
7)为用户表插入数据
insert into qquser values(1,1,'long','I'm long','male','[email protected]','48.gif');
insert into qquser values(2,2,'a','aa','male','[email protected]','48.gif');
insert into qquser values(3,3,'b','bb','male','[email protected]','48.gif');
insert into qquser values(4,4,'c','cc','male','[email protected]','48.gif');
insert into qquser values(5,5,'d','dd','male','[email protected]','48.gif');
8)为分组表和群表插入数据
insert into qqperson_group values(1,1,'my friend');
into qqpublic_group values(1,1,'ha ha','my new group');
9)为用户与群中间表插入数据
insert into qqperson_group(1,1,1);
insert into qqperson_group(1,1,2);
insert into qqperson_group(1,1,3);
insert into qqperson_group(1,1,4);
insert into qqperson_group(1,1,5);
10)为用户与分组中间表加入数据
insert into qqpublic_group(1,1,1);
insert into qqpublic_group(1,1,2);
insert into qqpublic_group(1,1,3);
into qqpublic_group(1,1,4);
insert into qqpublic_group(1,1,5);
2.3类图
图3.4 系统类图
Socket:非自定义类,java.net.Socket。
Thread: 非自定义类,java.util.Thread。
Client:负责具体发送和接收数据。
FromServerListen:监听服务器是否在发送数据。
MainFrame系统的主界面(包括用户列表等)。
QQUserInfo包括用户的好友分组信息和群信息。
QQUserClass包括用户的个人信息,如ID、用户名等。
3 详细设计及实现
3.1界面设计
1)登陆界面
本界面需要填写的有两个,一个是用户账号,另一个是用户密码。在客户端,用户输入其号码和密码,然后建立与服务器的连接,告诉服务器我要登录,服务器收到后,开始通过Jdbc方式读取数据库,然后与用户输入的信息比较,否则返回错误,如果客户收到成功信息就打开主窗口,否则提示出错。如果成功,便打开主程序窗口。然后客户向服务器请求读取好友名单,服务器收到该请求,开始读取数据库中的friend表,得到好友的号码后,再在好友表中读取好友资料,然后向客户端发送这些信息,客户收到后就在主窗口显示好友,并且建立几个Vector用以存储好友的信息。
图4.1 登陆界面图
2)注册界面
本界面要填写的项目包括:用户昵称,密码,邮件地址,个性签名。
需要选择的项目包括:性别,头像。
本界面主要负责将用户的信息包装成一个QQUserClass对象。注册按钮一旦被点击,就会试图创建一个与服务器端的连接。连接创建成功就会将填写的信息发送到服务器端。如果服务器写入数据库成功,就回返回一个账号。使用这个账号,用户可以登陆到系统中。
图4.2 注册界面图
3)主界面
主界面是系统的核心部分。它可以列出所有好友和客户所有加入的群,也可以提供共享文件和文件下载功能。如果用户服务双击好友分组或群,好友列表或群成员列表将会显示出来。双击一个好友,可以与他进行私聊。双击一个群成员,可以与群里的所有成员对话。本界面还提供了以下右键菜单:添加好友分组、查找好友并加为好友、查找群并加为群、创建群、移动好友到其它分组、查看好友资料、查看群资料。
图4.3 系统主要界面图
4)个人资料界面
该界面主要显示某个用户信息,包括用户的账号,昵称,性别,个性签名,用户等级等。
本界面还提供了一个“加为好友”按钮,如果点击它,此人将会被加为用户的好友。默认的是加到第一个好友列表,不过也可以移动其它好友分组。
图4.4 查看好友资料图
5)文件传输服务器端界面
该界面使用的步骤为:
第一步:设置好服务器的IP,端口。IP一定要是本机的IP,如果是单机测试,IP可以填写“127.0.0.1”。端口号尽量不要小于2000,小于两千的端口可能被系统占用。设置完后点击“确定”按钮。
第二步:添加共享文件。单击“添加文件共享”按钮,将需要共享的文件或文件夹添加到共享列表中。
第三步:点击“启动文件发送服务”。
第四步:如果共享文件完毕,需要点击“退出”。
图4.5 文件传送服务器
6)文件传输客户端界面
使用文件传输的客户端要正确配置好服务器的IP和端口号,以及下载好的文件的存放目录。如果其中之一配置不好,文件下载将会失败。设置好以后,点击“连接”按钮,如果配置正确,这时将会看到服务器共享的文件。目前不能支持文件夹下载和多文件下载,当看到一个文件以后,可以双击该文件夹并查看文件夹里面的文件。
图4.6 文件传送客户端
7)私聊界面
本界面主要用来显示两个人的对话信息以及发送信息。发送的信息可以设置字体,大小,字体颜色。也可以发送一个QQ表情。
图4.7 私聊界面图
8)群聊界面
本界面主要用来显示多人的对话信息以及发送信息。发送的信息可以设置字体,大小,字体颜色。也可以发送一个QQ表情。右边显示的是群公告,可以用来公布一些必要的信息。
图4.8 群聊天界面
3.2数据输入输出设计
3.2.1数据输入
3.2.1.1登陆界面数据的输入要求
Number(账号)输入的必须是整型,它是一个用户登陆的账号。
Password(密码)可以是你设置好的字符串,字符串内容可以随便。
如果用户设置不正确,将会导致登陆不成功,系统会弹出相应的对话框。
3.2.1.2注册界面的输入
Nickname(昵称),password(密码),sign(个性签名)可以是任意的字符串。
Email必须是Email地址格式,也就是中间必须含有“@”,否则提示输入不正确。
3.2.1.3共享界面的输入
服务器IP:填入本机的IP地址,格式如:172.168.1.253
端口号:随便一个可以未被占用的端口都行(最好是2000以上)。
3.2.2数据输出
用户注册的信息必须写入数据库中。
下载的文件存放到的指定的目录中,如果未指定就存放到默认路径中,当默认路径不存在的时候给提示用户路径不存在。
3.3代码实现
3.3.1服务器端设计
3.3.1.1 连接池的设计
连接池,就是生产一定数量的数据库连接存储在一个容器中,等待程序来索取,当这个容器器中的数据库连接全部被使用完的时候,就立即再产生指定数量的数据库连接。这样做的优点就是可以充分利用资源,减少创建和关闭所带来的资源消耗。在程序中它是以一个集合来存储这些连接的。如果访问的程序过多,而连接又少,连接池可以迅速增加多个连接以供程序需求。如果连接需求量超出连接池所设定的最高值。连接池将不理会程序的请求。
连接池主要由以下几个类创建:
(1)poolSet.properties
该文件的内容如下:
poolname=QQPool
user=root
password=root
url=jdbc:mysql://127.0.0.1:3306/javaqq
driver=org.gjt.mm.mysql.Driver
minconn=5
reuse=20
maxconn=1000
logfile=c:/QQPool.log
第一行声明要创建的数据库连接池的名字。第二行是访问数据库的用户名。第三行是访问数据库的密码。第四行是访问(mysql)数据库的url。第五行是声明驱动程序所在的类全名。第六行设定了数据库连接池中最少应保持的连接数。第七行设定了一个连接(Connection)最多可重复使用的次数。第八行设定了连接池是最多创建的连接数。第九行声明了一个日志文件(该日志文件记录的是数据库连接方面的信息)存放的路径。
(2)GetPoolSet.java,本程序的主要功能是获取上一配置文件中的信息,并将获得的信息返回给其他程序。由于代码过多,本文并不列出源代码只以表格的形式说明各方法的作用。
表4.1 GetPoolSet类的方法说明
方法名 |
作用 |
public void setFileName(String fileName1) |
设置将要访问的配置文件 |
public GetPoolSet() |
创建一个空的获取配置文件中信息的对象 |
public GetPoolSet(String fileName1) |
根据fileName1创建一个能猎取配置文件中信息的对象 |
public String getSet(String name) |
从配置文件取得信息,并返回给调用程序 |
(3)LogFile.java
本类主要用于记录日志信息,当程序出现异常的时候就会调用此类的方法将出错信息写如日志文件。
(4)ConnectionPool.java 本程序主要用于创建数据库连接。
表4.2 ConnectionPool的方法说明
方法名 |
作用 |
public ConnectionPool(GetPoolSet poolset) |
构造器,它创建一个ConnectionPool对象 |
public Connection createConnection(GetPoolSet poolset) |
真正创建ConnectionPool对象的方法 |
public Connection getConnection() |
获得连接 |
public void freeConnection(Connection conn) |
释放连接,返回给连接池 |
public void check() |
检查连接是否还正常 |
public void release() |
关闭连接 |
(5)PoolManager.java连接池管理,和对外交互的类,决定连接池的生产与销毁。
表4.3 PoolManager类的方法的说明
方法名 |
作用 |
synchronized public static PoolManager getInstance(String setfile) |
返回某个连接池的管理对象 |
synchronized public static PoolManager getInstance() |
返回默认的连接池管理对象 |
private PoolManager(GetPoolSet poolset1) |
构造器,创建连接池管理对象 |
private ConnectionPool createPool(GetPoolSet poolset) |
创建连接池 |
public Connection getConnection() |
获得连接 |
public void freeConnection(Connection connection1) |
释放连接 |
public void closemypool() |
关闭连接池 |
public void release() |
关闭所有的连接池 |
3.3.1.2 服务器端监听线程的设计
服务器在监听到一个客户以后,它就会创建一个线程去管理这个客户。至于如何去管理这个客户,服务器端不做任何干涉,完全由监听线程决定。监听线程主要对客户端的请求进行响应,做到有求必应。接收到信息后,首先判断该信息是哪种类型,如果是要访问数据库服务器,则直接根据发送信息内容操作数据库。如果是聊天内容,服务器会将该信息再次转发到目的地。这些判断将会全放部在一个线程的run方法中。
3.3.2传递包的设计
由于请求的服务不同,包的类型应该所区别。所以在设计的时候,应该在包中加一个存储包类型的属性并提供设置和获取这个属性的方法。以下就是对包抽象出来的应该有的方法,所有要传输的方法必须实现以下接口中的方法:
package javaqq.datagram;
import java.io.Serializable;
public interface DatagramPacket extends Serializable
{
// define class number for the packet which need to send to others
public static final int MESSAGESHOW_PIC_PERSONAL = 1;
public static final int MESSAGESHOW_PHOTO = 2;
public static final int MESSAGESHOW_WORD_PERSONAL = 3;
public static final int MESSAGESHOW_WORD_GROUP = 4;
public static final int MESSAGESHOW_PIC_GROUP = 5;
// define class number for the packet which not need to send to others
public static final int DATABASEHANDLE_FIND = 11;
public static final int DATABASEHANDLE_DEAL = 12;
public static final int DATABASEHANDLE_RESULT = 13;
public static final int DATABASEHANDLE_FLAG = 14;
public static final int USER_INFO = 21;
public static final int USER_LOGIN = 22;
public static final int USER_REGISTER = 23;
public static final int USER_REGISTERINFO = 24;
//find infomation
public static final int FIND_USER=31;
public static final int RETURN_USERINFO=32;
public static final int FIND_GROUP=33;
public static final int RETURN_GROUPINFO=34;
public static final int JOIN_GROUP=35;
public static final int RETURN_GROUPMEMBERS=36;
// system information
public static final int SYSTEM_INFO = 91;
public static final int SYSTEM_ON_OR_OFFLINE = 92;
public int getType();
public Object getData();
public long getFromuserid();
// if (getTouerid()==0),then the datapacket will be sended to server
public long getTouserid();
public String getTalkroomid();
}
服务器在接收包的时候,就调用它的getType()获得type的值,并采取相应的措施。
3.3.3聊天客户端设计
聊天窗口发送文件文字与图片的代码如下:
//发送文字
public void insertString(String s, SimpleAttributeSet attributset)
{
Try
{
doc.insertString(doc.getLength(), s, attributset);
doc.insertString(doc.getLength(), "\n", null);
showScroll.getVerticalScrollBar().setValue(
showScroll.getVerticalScrollBar().getMaximum()+20);
showText.setCaretPosition(showText.getDocument().getLength());
}
catch (BadLocationException e)
{
e.printStackTrace();
}
}
//发送图片
public void insertIcon(String str)
{
String picurl = TalkFrame.class.getResource("pic").getPath()
+ File.separator;
try
{
ImageIcon icon = new ImageIcon(picurl + str);
showText.setCaretPosition(doc.getLength());
showText.insertIcon(icon);
doc.insertString(doc.getLength(), "\n", null);
showScroll.getVerticalScrollBar().setValue(
showScroll.getVerticalScrollBar().getMaximum());
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
3.3.4文件传输设计
3.3.4.1文件传输客户端设计
从Socket中读取数据,并将数据写入到文件中,代码如下:
while (!stop)
{
int read = 0;
if (getDis() != null)
{
read = getDis().read(buf);
// 将数据读入缓冲区,并返回读取数据长度
System.out.println("read" + read);
}
Else
{
System.out.println("数据输入流不存在!");
break;
}
if (read == -1)
{
fileOut.close();
break;
}
System.out.println(read);
received += read;
System.out.println("写数据一次");
// 将缓冲区中的数据写入文件中
fileOut.write(buf, 0, read);
}// while
3.3.4.2文件传输服务端设计
从文件中读取数据,并将数据发送到客户端,代码如下:
while (!isStop())
{
int read = 0;
if (fis != null)
{
read = fis.read(buf);
// 从文件读取部分字节数据到buf缓冲区中
}
System.out.println("read:" + read);
if (read == -1)
{
// 若读到文件结尾,退出
break;
}
dos.write(buf, 0, read);
// 将buf缓冲区中的数据写入网络输出流
dos.flush();
}
4 系统测试
4.1注册测试
输入以下信息:
图5.1 注册填写图
得到:(登陆账号:46)
图5.2 返回注册账号图
4.2登陆测试
输入以下信息:(账号:1,密码:123)
图5.3 登陆填写图
登陆成功的结果:
图5.4 登陆成功后的主界面图
4.3私聊测试
1)首先登陆两个账号,如(账号1密码123,账号2密码123)
2)打开聊天窗口,如
图5.5 打开两个聊天窗口
3)相互发送信息
图5.6 两人相互发送信息图
4.4群聊测试
1)首先登陆三个账号,如(账号1密码123,账号2密码123,账号3密码123)
2)打开三个对话窗口
3)各发一条信息(如:我是某某)
结果为:
图5.7 群聊测试图
4.5文件传输测试
1)登陆账号1密码123,启动文件传输服务器端(),设置本机IP地址,添加共享文件
图5.8 文件发送端测试图
2)登陆账号2密码123,设置服务器端口与IP,并点击连接按钮
图5.9 文件发送客户端测试1
选中一个文件并添加到下载列表,点击下载按钮。
图5.10 文件发送客户端测试2
成功下载的文件:
图5.11 下载后的文件
结 论
用java开发GUI系统,比较麻烦的一点界面的设计。主要包括两个方面:组件不能随意设置背景图片、布局比较困难。目前有的工具(如netbeans,JBuilder)在这这布局方面可能比较好,但是手动更改代码非常不方便。关于背景的设置就更不好解决,设置颜色还可以办到,要想设置背景图片,那就得自己去重写某个类了。本系统重写的类有JPanel、DefaultTreeCender、DefaultMutableTreeNode等。其中JPanel重写了一个方法后可以设置背景图片,不过图片对象只能在构造器中传入。DefaultTreeCende和DefaultMutableTreeNode的重写是为了可以构建一个带有自定义图标的数组件。
对于文件传输模块,我本来想做成具备多文件下载和文件夹下载的功能的程序。但是有一点使我感到很困惑的是DataOutputStream对象一旦传输了byte数组,如果再传输字符串就会出现异常。为了避开这个问题,我以为把所有字符串转换成byte数组,然后再转换成字符串就可以解决问题。可出乎我的意料之外的是,这样解决会更加困难。这样做的困难是,假如有两个字节数组A和C,另外有一个字符串(假如这个字符串表示一个文件的开始,如“fileTransferStart”)转换成的字节数组B。当服务器把A、B、C三个数据依次发送出去后,客户端接收的B不再是B,它有可能与A混在一起,也有可能与C混在一起,也有可能A、B、C同时混在一起。当B代表着一个文件的结束与另一个文件的开始的时候,客户端程序就无法区分了,它会将多个文件的数据全部写入到一个文件。这样话的,这个文件就报废了。我对于这个问题的理解是,字符数组在网络传输的时候可能会进行重组,把多个非常短的数组合并成一个长度适中的数组,这样可能会节省资源开销吧。对于什么时候合并成一个数组我就不知道了。还有一种思路就是,把所有的字节数组类型的数据换成字符串,再通过字符串传输到客户端,客户端接收以后,首先判断这个是不是正常的字符串,如果不是就把它转换成byte数组写入文件中。因为时间的关系没来得及验证这种想法。就算这种想法可以,也会在效率上大打折扣,毕竟把byte数组转换成字符串和把字符串转换成字节数组是需要时间的。
致 谢
参 考 文 献
[1] 王昆,张力生.Java Swing中的渲染器机制.重庆工学学院报,2008,22(10):175~178.
[2] 吕校春,李玲莉.基于Swing的Java GUI组件开发[J].机械工程师,2008(5):129~131.
[3] 陆维厅,邵燕.基于JAVA的SOCKET实现网上交谈.河海常州分校学报,2005,3(14):31~35.
[4] 戴歆.JAVA Swing程序开发.软件导刊,2007,2(6):22~29.
[5] 莫足琴.基于Java Socket多客户端并发通信聊天程序的设计与实现.十堰职业技术学博士论文,2008:253~255.
[6] 王静,曲凤娟.基于Socket的多用户并发通信的设计[J].福建电脑,2007(3):164.
[7] 赵文清,姜波.基于Socket的Java语言网络通讯机制和程序设计.信息技术,2006,8(7):66~67.
[8] 温涛.工程概念.软件工程师,2006(1):16~18
[10] 朗波.JAVA语言程序设计.清华大学出版社,2005:189~190.
[11] 曹健.计算机软件发展.IT时代周刊,2005(2):12~15
[12] 周燕飞,左敦稳,李亮.数据库原理与应用.北京:机械工业出版社,2003:78~89.
[13] 张景中.应用计算机.计算机应用,2008(1):23~28.
[14] Ian Somerville. Software engineering.北京:机械工业出版社,2004:73~84.
[15] Paul C.Jorgensen. 软件测试.西安:机械工业出版社,2003:134~139.
[16] 赵池龙,姜义平,张建. 软件工程实践教程. 北京:电子工业出版社,2006:160~185.
[17] 萨世煊,王珊. 数据库系统概论(第三版). 北京:高等教育出版社,2006,23~100.