基于Socket的网络即时通信系统报告.docx
《基于Socket的网络即时通信系统报告.docx》由会员分享,可在线阅读,更多相关《基于Socket的网络即时通信系统报告.docx(31页珍藏版)》请在冰豆网上搜索。
基于Socket的网络即时通信系统报告
网络信息处理课程
设计报告
题目:
基于Socket的网络即时通信系统
班级:
小组成员:
指导教师:
中国矿业大学电脑学院
2013年6月
1.需求分析
1.1开发背景
即时通信系统是基于Internet网络及其它有线、无线网络的一种非常流行的实时通信方式,是一种非常便捷的网络通讯技术,它用互联网通过通信系统建立起网络虚拟环境,通过电脑键盘或无线设备在网络上进行实时交换,成为一种提供公共通讯、商务通讯及商务合作的新媒介,也弥补了传统通讯形式的不足,尤其是电子邮件及语音通信方面。
随着即时通信普及,全球即时通信用户的数量也不断增长。
微软公司的MSN、腾迅公司QQ、网易公司的网易泡泡等通信系统都是家喻户晓的。
除了最基本的单纯的文本交流,即时通信业务增加了视频、音频交流等多种宽带应用元素,如提供视频、语音通信服务、交流共享、短信收发、数据传输等服务项目。
即时通信业务的承载设备也将趋向于多元化。
用户可以通过、个人电脑、PDA等工具使用即时通信,宽带、网络业务也逐渐在即时通信的软件上实现功能。
本文所介绍的网络即时通信系统是基于开放的JAVA应用程序开发设计的,其主要特性是能动态、实时的完成信息的传递,且具有高效的交互性。
该设计有一个服务器和假设干个客户端,服务器、客户端和客户端、客户端之间可以实现群聊与私聊,客户端之间可以进行文件传输。
该设计可以应用于公司或者学校,因为是自己提供服务器,方便管理各个用户。
1.2系统目标
该系统目标是提供信息交互等基础服务,它既可以用TCP可靠的运输服务,也可以使用UDP运输服务。
这个即时通信系统是一个类似QQ的聊天系统,有客户端和服务器端。
服务器端记录当前在线客户列表,把客户列表发送给每一个在线客户,并实时刷新。
任一个客户可以和任意其它的客户进行交互,即从在线客户列表中选择一个或一组其它客户通过服务器转发彼此进行交互,包括信息交互,文件交互。
本系统是基于Socket进行通信,要求有两台或两台以上的能正常进行网络通信的电脑,并且已经接入了同一个网络,每一台电脑都有一个固定且在网络中唯一的IP地址。
主要思路和操作流程
〔1〕设计服务器端和客户端的界面
服务器的界面设置启动服务器和关闭服务器的按钮,用户列表框来显示当前已登录的用户,用来发送系统消息的文本框,用来发送系统消息的按钮,和一个文本框来显示各种信息,比方显示系统信息,以及用户登录信息,服务器开启或关闭的信息。
客户端界面设置一个菜单栏,菜单栏里有操作,设置,和发送文件三个主菜单。
操作主菜单应该包括登录、注销和退出三个子菜单;设置包括用户名〔用来设置用户名〕,连接两个子菜单〔用来与服务器进行连接〕;发送文件主菜单有一个发送文件的子菜单〔用来发送文件〕;客户端还用来设置用户名,与服务器建立连接,登录服务器,注销,文件接收和发送消息六个按钮,还设置一个下拉列表框来显示所有已经登录的用户名及其IP〔这里设置IP的目的是为了实现文件的传输〕,一个用来显示用户头像的标签〔所有用户的头像设置为同一张图片〕,一个用来发送消息的文本框,一个用来接收信息的文本框。
〔2〕设计消息传送的协议
对消息的传送,分为服务器端和客户端两部分:
服务器端,发的消息为系统消息,客户端发送的消息根据消息接收对象的个数的不同又分为私聊信息和群聊信息。
〔3〕设计文件传送的协议
首先,发送端从服务器获得接受端的IP,接着发送端和客户端建立连接,传送文件。
1.4相关技术
.1JAVA语言
Java是一种简单、多线程、安全、容易适用、可移置、面向对象、高性能的语言。
它具有如下特点:
1.面向对象:
面向对象技术是一次革新,它可以提高模块化程度和重复适用率,缩短软件开发时间,减低开发成本。
2.安全性:
Java提供了许多安全机制,是能用在网路和分布环境下的程序设计语言。
3.多线程:
Java具备内建的多线程功能,使各线程并发、独立执行,提高系统的运行效率。
4.平台独立:
平台独立是指程序不受操作平台限制,可以应用于各种平台。
Java源程序经过编译后能够生成字节码文件,字节码和具体的电脑无关。
电脑安装能解释执行字节码的JVM,就能执行字节码文件,实现了Java的平台独立性。
5.执行效率:
字节码要经过JVM解释成机器码才能执行,所以速度较慢。
.2TCP/IP协议
TCP协议是网络通信的基石。
Java专门提供了Socket的类库,抽象出TCP协议通信中的常用方法:
TCP协议与三次握手:
〔1〕客户端,首先发送TCP请求,客户端是服务〔如数据查询服务〕的请求者。
〔2〕服务器,接收到客户端的请求后,服务器向客户端提供服务。
服务器是服务的执行者,返回服务执行的结果给向客户端。
ACK=1
第一次握手,主机A向主机B发送连接请求
第二次握手,主机B收到主机A的请求,向主机A回发一个确认,,同时向主机A发送一个连接请求
第三次握手,主机A收到主机B发送的数据包在向主机B发送一个确认连接
主机A主机B
SYN=1,SEQ=0
ACK=1,SYN=1,SEQ=1
aaaaaaaaaa
图1-1握手协议
首先客户端发送一个数据包SYN。
如果服务器收到SYN,它会发回一个数据包SYN+ACK。
客户端为了表示收到SYN+ACK信息,向服务器发送一个最终确认信息ACK。
SYN,SYN+ACK,ACK步骤被称为“三次握手”,这样,连接就建立好了,并将一直保持活动状态,直到其中一方发出FIN〔结束〕信号或者超时。
这种通信模式也被叫做客户端/服务器〔C/S〕模式。
.3Socket通信
图1-2Socket实现原理图
从概念上理解,Socket是网络编程中最常见的客户/服务器模式,也是本系统的基础。
以该模式编程时,服务器端有一个进程或多个进程在指定的端口等待客户来连接,一旦连接成功,便按设计的数据交换方法和格式进行数据传输。
客户端向服务器端提出连接请求,连接之后进行通信。
Socket是一种用于表达两台机器上都有一个Socket,可以想象一条虚拟的电缆工作在两台机器之间,电缆插在两台机器的Socket上。
简单的说,一台电脑上的Socket同另一台电脑通话创建一个通信信道,我们可以用这个信道在两台机器之间发送数据。
如图2-2Socket实现原理图。
1.5开发工具与开发平台
本次开发是基于操作系统MicrosoftWindows7,开发工具为JDK,开发平台为eclipse。
2.概要设计
2.1系统功能描述
我们的程序功能分为两个部分,即发送消息部分和发送文件部分
(1)发送消息:
首先开启服务器端,并且在服务器端开启服务,然后在客户端设置服务器端的IP地址和自己的用户名,以便于与服务器端的连接与用户的识别,然后登录服务器并建立连接,在自己的客户端中的下拉列表框中选择选择要发送消息的对象或者是默认选择发送消息至所有人,最后点击发送。
由于我们的聊天程序是基于服务器端的消息转发机制,所以如果用户选择发消息给自己的时候,就会显示2条信息,第一条是自己的客户端输出到聊天的文本框中的,第二条是服务器把消息转发给我自己的客户端然后输出到聊天的文本框中的。
当然,我们在服务器端也是可以发消息的,在客户端收到的消息都会显示为系统消息加上你在服务器端输入的消息。
(2)发送文件:
在与服务器端建立连接的条件下,客户端从服务器端获得所要发送文件的对象的IP地址,然后通过原有的发送消息的机制,把我要发送文件的消息发给服务器进行转发,当另外一个客户端收到对方要发送文件的信息后也通过原有的发送消息的机制,把我接收文件的消息仍然交给服务器进行转发,并且从服务器端获得要发送文件的那个用户的IP地址。
当双方都收到消息后,即可建立连接发送文件,在文件发送完毕,在这两个客户端都实时显示文件发送完毕的信息。
2.2系统架构
图1中的是我们在两个用户的情况下整个聊天程序的系统架构,并且这两个用户是有传输件的需求的。
我们的聊天程序是多个用户的连接,我们的聊天程序是基于消息的服务器转发机制,即将所有要发送的消息都提交到服务器,然后由服务器转发,然后由服务器进行识别是多人聊天的信息还是私人聊天的信息。
如果是多人聊天,即转发到所有的用户,如果是私人聊天,转发到要发送的用户的客户端去。
用户之间传输文件及进行点对点通信
服务器
客户端1
客户端2
与服务器传输信息
与服务器传输信息
图1
考虑到传输效率方面的问题,以及隐私方面的问题,我们的文件传输机制没有用基于服务器转发机制实现,而是利用消息转发机制进行协议的控制,而后用一个新的端口号,建立双方的TCP连接直接传输文件。
文件传输完毕后,双方都关闭各自的传输文件的socket。
2.3模块划分
客户端模块
信息封装
+“XX”+“文件传输”
信息封装
+“XX”〔或者“所有人”〕
我们的模块划分为服务器端以及客户端的发送消息部分和客户端的发送文件部分。
由于服务器端只是负责建立多方之间的连接以及消息的转发,所以做成一个单独的模块,而客户端有发送文件或者是发送消息的需求,所以这两个分别做成客户端的两个线程,形成客户端模块(如图2)。
图2客户端模块
服务器端模
图3为服务端模块,服务器对客户端进行解析信息,以及对各客户端传来的信息进行判断传递同时判断各客户端传来的信息是什么类型,需要传输消息或者是文件。
解析带“所有人”的信息
解析带“文件发送”的信息,并发送发送端IP和端口号
服务端
发送私聊信息
为发送文件发送IP和端口号
广播群聊信息
解析“XX”〔接收端〕的信息
图3服务器端模块
3.详细设计
流程图
系统总体流程图
客户端流程图
3.2数据结构
3.2.1服务器端设计
〔1〕
Public类主要功能是服务器端的界面设计,添加窗体中组件的事件侦听,响应相应事件处理。
并调用Listener类来实现对客户端用户的上线与下线的监听,和实现服务端对客户端的发送系统消息。
主要功能函数:
actinPerformed主要对于窗体按键的响应,实现服务器端的启动服务,停止服务,和服务端对在线用户的消息发送。
startService启动服务器的工作
stopService停止服务器的工作
sendStopToAll对所有客户端发送服务器停止工作的消息
sendMsgToAll对所有客户端发送服务器的系统消息
sendSystemMessage对单个的客户端发送系统消息
(2〕ServerListen.java
Listener类主要功能是实现服务器端对于客户端的用户的上下线进行监听。
通过调用类(ServerReceive类〕来实现。
当用户发生变化时会对服务端的主界面进行相应的修改。
主要功能函数:
run实现客户端的上线情况监听,并调用Receiver类来实现客户的更新和对于客户端到客户端的消息转发。
(3)UserLinkList.java
UserLinkList类是用户列表,用用户链表节点实现,该类通过构造用户链表,定义了添加用户,删除用户,换回用户数目,根据用户名查找用户。
主要功能函数:
addUser对用户链表添加新用户
delUser删除链表中的用户
getCount返回链表中记录的用户数量
findUser通过用户名称查找用户。
3.2.2客户端设计
〔1〕
ChatClient类主要是实现客户端的界面,添加对于客户端界面的组件事件侦听与事件处理。
调用ClientRecieve类实现消息的收发。
主要功能函数:
actionPerformed响应窗体的组建事件,实现用户信息的配置,与服务器端的连接和断开连接,客户端的信息发送,以及客户端对客户端的点对点的文件传送。
Connect实现用户端与服务器的套接字连接,并创建ClientRecieve实例来实现从服务器端获得消息。
DisConnect关闭与服务器端的连接。
SendMessage实现客户端的对在线用户的发送消息。
〔2〕
ClientRecieve线程类主要是实现客户端对于服务器端的消息接收。
主要功能函数:
run线程体不断的监听端口消息信道,从中获得服务器端只能够发送的各种消息。
〔3〕FileSend.java
FileSend线程类,实现文件的发送,当用户需要点对点的文件传送,调用此类。
主要功能函数:
selectfile在客户端选择要发送的文件
Sendfile当用户连接到时把文件从本地发送到接受端。
Run线程体实现对于文件发送端口的监听,等待用户的连接。
〔4〕
Uploadserver线程类,实现与文件发送端的套接字连接,然后调用FileRecieve类实将文件下载到本地。
主要函数:
run线程体,实现套接字连接
FileRecieve线程类具体实现与文件发送端口的回话,将文件下载。
主要函数:
run线程体,实现文件下载。
〔5〕
ConnectConf类实现用户连接信息的配置,设置连接服务端的ip。
UserConf.javaUserConf
UserConf类,实现用户信息的修改,主要是用户名称修改
N
S
U
3.3协议结构
.1消息传送协议
〔1〕服务端:
服务器端发的消息是系统消息,系统消息发给所有用户〔见图4〕;服务器要发送系统消息,服务器经判断后将其传给所有用户,或者构成对单个用户的系统信息。
〔2〕客户端:
发送端从保存有用户名的下拉列表框中选择接收消息的对象,如果选择发送给所有用户,则为群聊信息,服务器发送给所有用户〔见图4〕;用户1要发送一条群聊信息,当服务器收到这条消息后判断消息的类型,得知是去聊信息后就将它传给所有的用户。
假设发送给特定的某一用户,服务器在用户列表找到该用户然后转发消息〔见图5〕,用户1要跟用户2通信,发出一条1到2的消息,当系统收到这条消息后首先判断它是不是系统消息,如果是,则广播这条消息,如果不是,则判断它是不是群聊信息,如果是则广播这条消息,如果不是,则服务器判断它为私聊信息,并从接收到的消息中提取出接收消息的客户名,并将它转发给这个用户。
对于消息的传输,在服务器端,先建立端口侦听,当客户端登录时,由于客户端知道服务器端的IP及端口,可以很快找到服务器,服务器监听到客户端请求,于是两端建立连接。
通过对信息的封装进行通信。
假设是群聊,则在前面添加“所有人”,然后信息传输到服务器后,服务器接收到客户端的信息,将信息进行验证、查找,发现前面封装的信息为“所有人”,可以认定该信息为群聊信息。
于是服务器对信息进行广播,让每个客户端都收到信息。
假设是私聊,客户端从服务器的列表中找到所需私聊的对象,然后在给信息添加XX〔接收端〕的信息进行封装。
当信息传送到服务器时,服务器解析,得到需要传输的对象,在将发送端的客户以及信息传送给接收端。
图4
图5
.2文件传送协议
发送端发送一条消息提示接收端我要发文件,并从服务器获得接收端的IP地址,建立通信双方的TCP连接。
如图6,用户1要向用户2发送文件,首先发送一条请求消息,从服务器获得用户二的IP,等待确认消息;当用户2收到请求消息之后,向用户1发送确认消息,并从服务器获得用户1的IP;当用户1收到确认消息后,与用户2建立连接,传送文件,用户1为文件发送的服务端,用户2为文件发送的客户端。
该操作属于面向连接的操作,应用了TCP协议,建立了客户发送端1与客户接收端2的连接,然后传递文件。
对于该连接来说,这里进行是先在发送端建立了一个服务器,采用与信息传输以为另外一个端口号,启动线程监听。
当接收端从服务器接收到发送传来的消息,该消息包括发送端的IP以及发送端建立的服务器的端口号以及“XX”〔接收端〕“发送文件”的信息,当服务器接收到时,解析该信息,从封装信息中取出“发送文件”以消息形式传给接收端,同时将发送端的IP以及发送端的新建的端口号传给接收端,于是接收端利用服务器转发而来的IP与端口号向发送端发出连接请求,当发送端接监听到接收端时连接建立。
然后当接收端通过服务器向发送端发送接收请求时,发送端即发送文件给接收端,完成文件传输。
由用户1向2传输文件
图6
4.软件测试与代码分析
服务器
服务器端启动界面
//启动服务端
publicvoidstartService(){
try{serverSocket=newServerSocket(port,10);//
messageShow.append("服务端已经启动\n");
startServer.setEnabled(false);
startItem.setEnabled(false);
stopServer.setEnabled(true);
stopItem.setEnabled(true);
sysMessage.setEnabled(true);
}catch(Exceptione){
e.printStackTrace();
}
userLinkList=newUserLinkList();
listenThread=newServerListen(serverSocket,combobox,
messageShow,showStatus,Userlist,userLinkList);
中将以上的操作进行刷新
listenThread.start();
}
4.1.2服务器端停止界面
//关闭服务端
publicvoidstopService(){
try{//向所有人发送服务器关闭的消息
sendStopToAll();
listenThread.isStop=true;
serverSocket.close();
intcount=userLinkList.getCount();
inti=0;
while(iNodenode=userLinkList.findUser(i);
node.input.close();
node.output.close();
node.socket.close();
i++;
}
stopServer.setEnabled(false);
stopItem.setEnabled(false);
startServer.setEnabled(true);
startItem.setEnabled(true);
sysMessage.setEnabled(false);
messageShow.append("服务端已经关闭\n");
combobox.removeAllItems();
combobox.addItem("所有人");
}catch(Exceptione){
e.printStackTrace();
}
}
服务器端发送系统消息
//向客户端用户发送系统消息
publicvoidsendSystemMessage(){
StringtoSomebody=combobox.getSelectedItem().toString();
Stringmessage=sysMessage.getText()+"\n";
messageShow.append(message);
//向所有人发送消息
if(toSomebody.equalsIgnoreCase("所有人")){
sendMsgToAll(message);
}
else{
//向某个用户发送消息
Nodenode=userLinkList.findUser(toSomebody);
try{node.output.writeObject("系统信息");
node.output.flush();
node.output.writeObject(message);
node.output.flush();
}catch(Exceptione){
}
sysMessage.setText("");//将发送消息栏的消息清空
}
}
客户端
客户端连接设置界面
//保存按钮的事件处理
save.addActionListener(
newActionListener(){
publicvoidactionPerformed(ActionEventa){
intsavePort;
StringinputIP;
//判断端口号是否合法
try{userInputIp=""+InetAddress.getByName(inputIp.getText());
userInputIp=userInputIp.substring
(1);
}
catch(UnknownHostExceptione){
DLGINFO.setText("错误的IP地址!
");
return;
}
//判断端口号是否合法
try{savePort=Integer.parseInt(inputPort.getText());
if(savePort<1||savePort>65535){
DLGINFO.setText("侦听端口必须是0-65535之间的整数!
");
inputPort.setText("");
return;
}
userInputPort=savePort;
dispose();
}
catch(NumberFormatExceptione){
DLGINFO.setText("错误的端口号,端口号请填写整数!
");
inputPort.setText("");
return;
}
}
}
);
//关闭对话框时的操作
this.addWindowListener(
newWindowAdapter(){
publicvoidwindowClosing(WindowEvente){
DLGINFO.setText("默认连接设置为127.0.0.1:
8888");
}
}
);
//取消按钮的事件处理
cancel.addActionListener(
newActionListener(){
publicvoidactionPerformed(ActionEvente){
DLGINFO.setText("默认连接设置为127.0.0.1:
8888");
dispose()