计算机网络课程设计聊天室.docx
《计算机网络课程设计聊天室.docx》由会员分享,可在线阅读,更多相关《计算机网络课程设计聊天室.docx(30页珍藏版)》请在冰豆网上搜索。
![计算机网络课程设计聊天室.docx](https://file1.bdocx.com/fileroot1/2023-8/18/be26b8c7-6cab-4433-b5ad-94a09d17d0ab/be26b8c7-6cab-4433-b5ad-94a09d17d0ab1.gif)
计算机网络课程设计聊天室
计算机网络课程设计报告
学生姓名
学号
班级计算机0908班
指导教师
设计时间2012.1.7~2012.1.10
目录
第一章设计目的、任务
1.1设计目的·························3
1.2设计的任务·······················3
第二章系统分析设计
2.1系统流程分析······················4
2.2系统功能需求分析···················5
2.3系统运行要求······················6
2.4系统数据要求······················6
第三章系统实现
3.1系统界面设计·····················7
3.2系统功能模块设计···················9
第四章体会和建议
第一章设计目的、任务
1.1设计目的
1.了解通信规范的细节及其实现。
2.通过本次网络课程设计,掌握高级编程语言中对用户界面的设计方法,以及多线程技术、基于TCP/IP的Socket通信的编程方法,同时能够把协议的设计思想应用到实际中去。
1.2设计的任务
编写一个聊天室,实现C/S模式的会话。
基本要求可以完成群聊、私人聊天,实时发送和显示聊天信息,完成好友列表;进一步要求带表情,附件发送,聊天信息的加密传送,设置黑名单等。
学习通信编程Socket接口编程,使用TCP或UDP接口完成信息传送,利用多线程技术实现服务器端的多个TCP连接的建立。
网络聊天是网络编程的典型应用之一,编写网络聊天软件对于学习网络编程无疑有着很大的帮助。
第二章系统分析设计
2.1系统流程分析
该C/S模式的聊天系统,就是服务器来提供服务端连接响应,客户端主动的发起连接请求。
当多个用户同时连接到服务器时,经由服务器的接收与转发便可以实现客户之间的通信。
因此,系统需要实现服务器端和客户端两部分程序。
下图是基本的客户端连接服务器的流程图。
Client
Server
建立连接
开始通信
结束通信
对于整体系统的流程,也是分为两部分,即客户端的发起请求,服务器响应请求。
首先是客户端的登陆,客户端在登陆时,必须设置所想要连接的服务器,然后客户端就会根据设置的服务器IP地址,向服务器发起建立连接请求。
而服务器端是始终在监听网络状态的,主要检测到有一个连接请求,那么服务器就会给当前的发起端分配一个服务线程,用于处理它的各种请求。
对于客户端的各种请求,实际上都是通过在客户发往服务器的各种字符流区分的,具体的方法就是在消息的头部以及尾部添加特殊字符串,从而实现服务器对消息请求的识别。
比如对于登陆信息,消息的头部就是“PEOPLO”,而对于私聊中的消息,头部就是“SEC”,其他的同理都添加了头部。
当然,对于客户端来说,这些都是透明的,用户的操作并没有受到任何影响。
在服务器端,消息被检测分析后,变回根据具体的目的进行处理,比如是私聊消息,服务器便会根据其尾部的目的信息,向目标端转发该条消息。
这里额外要说的是,该系统特别的对用户发来的消息进行了加密处理,即用户的各种具体信息,不仅能够防止向第三方的泄漏,而且即使服务器端出现异常,信息也不会泄漏。
对于私聊的方式,该系统所采用的方法类似于QQ的通信方式,由发起方主动连接,当目的方接收到连接请求后,会主动建立一个私聊窗口,从而实现私聊。
2.2系统功能需求分析
本系统所要实现的主要功能是为用户提供一个借助网络进行人际交往的平台。
因为服务端采用多线程,所以性能有很大提升。
因为服务端和客户端之间采用TCP/IP协议进行网络通信,建立的是可靠的、端到端的网络连接,所以可靠性和安全性都很好。
本系统主要通过客户端,服务器端来体现聊天系统的基本功能,两者主要的功能如下所示。
(1)服务器端
1.处理用户登录
2.处理用户的各种信息,包括状态信息、聊天信息等
3.监控聊天内容,过滤非法内容,并对不法用户实现拉入黑名单
4.处理用户退出
(2)客户端
1.用户登录
2.用户发送信息
3.用户接收信息
4.用户之间的群聊
5.用户之间的私聊
6、消息发来时,发出提示声音
7.显示当前在线用户列表,并且同步更新
8.用户私人信息的加密处理
9.用户退出
2.3系统运行要求
运行环境:
Windows9x、2000、XP、Windows7
必要环境:
JDK1.6以上、eclipse开发环境
硬件环境:
CPU400MHz以上,内存512MB以上
2.4系统数据要求
1、系统中数据的传送是以字符串的形式传送的。
对于不同请求信息的区分是通过在字符串的头部添加系统信息实现的。
这些系统信息包括:
PEOPLO、QUIT、SEC、MIMI、MSG。
PEOPLO代表该条信息是用户的登陆信息,QUIT代表该条信息是用户的登出信息,SEC代表该条信息是用户的私聊信息,MIMI代表该条信息是用户向另一个用户发起的建立私聊请求,MSG代表该条信息是用户发出的公聊信息。
2、在系统中,用户发出的各种私人信息都是在客户端进行加密的,然后服务器端转发到另一个用户后,在用户端再进行解密处理。
第三章系统实现
3.1系统界面设计
1、服务器端
(1)服务器运行中的界面图如下所示:
2、客户端
(1)客户端运行后的登陆界面图如下所示:
(2)客户端运行后的主界面图如下所示:
(3)客户端运行后的私聊界面图如下所示:
3.2系统功能模块设计
1、服务器创建Serversocket,使用本地IP以及端口(port)1234建立套接字对网络进行监听,并对发来请求的客户创建连接,分配服务线程firstthread。
实现该功能的代码如下所示:
listen=newServerSocket(PORT);//创建一个服务器,进行监听
try{
while(true)//保持监听客户端的请求
{
Socketclient=listen.accept();//服务器监听
st.append("\n新客户机器的IP地址:
"+client.getInetAddress());
firstthreadf=newfirstthread(this,client);
//为每一个客户创建一个客户端线程
f.start();//客户端线程启动
clients.addElement(f);//将面向客户端的线程加入向量列表中
st.append("\n聊天室当前人数:
"+clients.size()+"\n");
//添加显示新用户的信息,当用户退出时可以把新的数量提示服务器显示
}
}catch(IOExceptione){
System.err.println("error:
"+e);
System.exit
(1);
}
2、服务器端对用户发来的头部带有MSG的公聊消息,进行广播。
下面是实现对消息进行广播,即发往所有用户的功能模块:
publicvoidbroadcast(Stringmsg){
firstthreadyou;
for(inti=0;iyou=(firstthread)clients.elementAt(i);
try{
you.out.writeUTF(msg);//向输出流写入信息
}catch(IOExceptione){
}
}
}
2、服务器端对用户发来的头部带有SEC的私聊消息,进行单播。
下面是实现对消息进行单播,即发往某单个用户的功能模块:
//向某个人发送悄悄话
publicvoidbroadcast1(Stringmsg){
Strings1,s2,s3;
firstthreadyou;
s1=newString("PEOPLE");//加上PEOPLE表示为新人消息
s2=newString(msg.substring(3));//“SEC"为3个字符所以从第3个开始截取
s3=s1.concat(s2);//连接字符串
for(inti=0;iyou=(firstthread)clients.elementAt(i);//取出第i个客户
intk=you.name.indexOf("]");//】出现的位置,即可知整个用户名
if(s3.startsWith(you.name.substring(0,k+1)))
//name格式为:
PEOPLE+名字+[性别],截取前一段按照其查找相应的用户
{
try{
you.out.writeUTF(msg);
}catch(IOExceptione){
}
}
}
}
4、当服务器与客户端建立连接后,服务器会对每个客户建立一个服务线程,用于处理客户发来的各种请求。
实现该功能的代码如下所示:
//firstthread构造函数
publicfirstthread(Serverserver,Socketclient){
//server参数用来调用公用的函数广播与单播
this.server=server;//必须做,因为要把参数传送给firstthread类的变量
this.client=client;
try{
in=newDataInputStream(client.getInputStream());
//获取向客户端的输入流
out=newDataOutputStream(client.getOutputStream());
firstout=newDataOutputStream(client.getOutputStream());
}catch(IOExceptione){//输出输出流抛出异常
try{
server.clients.removeElement(this);//在客户表中删除
client.close();//关闭socket
}catch(IOExceptione2){
System.err.println("连接出现问题,请修复~"+e);
return;
}
}
}
5、服务器端为客户端建立的线程主要实现的是对客户发来的各自消息的分析识别,即对消息头部的识别。
实现该功能的代码如下所示:
//面向客户端的线程始终监听
try{
while(true){
line=in.readUTF();//line读取来自客户端的信息
Mimasx=newMima();
//信息开头为PEOPLE,表明有新用户进入了聊天室,则给当前的面向客户的服务线程赋值
if(line.startsWith("PEOPLE")){
try
{
firstthreadd=(firstthread)(server.clients.elementAt(server.clients.indexOf(this)));
//this为发送新的的当前对象,则获取其线程
d.name=line;
//因为当前的用户名字就在line中,所以可以将line直接复制给当前线程的name变量
}catch(ArrayIndexOutOfBoundsExceptione){
}catch(NullPointerExceptione){
}finally{
server.broadcast(line);
//向聊天室所有人员发送有人进入聊天室信息,在各自的显示区显示欢迎信息
}
}
//以QUIT开头表明有人离开了聊天室
elseif(line.startsWith("QUIT")){
Stringstr2=this.name;
str2=str2.substring(6);//在服务器显示退出者的姓名
server.broadcast("QUIT"+this.name);
server.clients.removeElement(this);
server.st.append("\n当前退出者:
"+str2+"\n");
//添加显示新用户的信息,当用户退出时可以把新的数量提示服务器显示
server.st.append("\n聊天室当前人数:
"+server.clients.size()+"\n");
//添加显示新用户的信息,当用户退出时可以把新的数量提示服务器显示
this.in.close();
this.out.close();
this.firstout.close();//关闭输入输出流
this.client.close();//关闭socket
this.yield();//线程放弃执行权
}
//线路信息前端为MSG表明接收到的是广播
elseif(sx.jieMi(line,"a").startsWith("MSG")){
intn;
intssss=0;
line=sx.jieMi(line,"a");
n=line.indexOf("abc");
if(n>=0){
Stringas1="MIMI".concat(line.substring(3,line.indexOf("]")+1)).concat("服务器[]");
JOptionPane.showMessageDialog(null,as1);
as1=sx.jiaMi(as1,"a");
server.broadcast2(as1);
Stringas="SEC".concat(line.substring(3,line.indexOf("]"))).concat("你已经因敏感词汇被拉入黑名单!
!
(服务器)");
as1=sx.jiaMi(as1,"a");
server.broadcast1(as);
}
else{
line=sx.jiaMi(line,"a");
server.broadcast(line);
}
}
//线路信息前端为“SEC”表明接收到的是单播
elseif(line.startsWith("SEC")){
this.out.writeUTF(line);//在自己的文本区显示
server.broadcast1(line);//在对方文本区显示
}
//MIMI
elseif(line.startsWith("MIMI")){
server.broadcast2(line);//在对方文本区显示
}
//线路信息前端为newlist表明得到客户端刷新列表的请求
elseif(line.startsWith("newlist")){
try{
for(inti=0;ifirstthreadc=(firstthread)(server.clients.elementAt(i));
if(c.name!
=null){
try{
firstout.writeUTF(c.name+"*");//更新列表
}
catch(IOExceptione){
}
}
}
}catch(ArrayIndexOutOfBoundsExceptione){
}catch(NullPointerExceptione){
}
}
}
}catch(IOExceptione){
server.clients.removeElement(this);//抛出异常的话就删除该线程
}catch(NullPointerExceptione){
server.clients.removeElement(this);
}
}
6、当客户端登陆成功后,客户端会产生聊天室主界面。
实现该功能的代码如下:
publicvoidinit(Stringhost){
setLayout(newBorderLayout());//布局管理器
b=newBpanel();
c=newCpanel();
setBounds(wx/2-300,hy/2-300,777,600);
setTitle("姗姗聊天室");
ImageIconicon=newImageIcon("src/qq/images/qqlogo.png");//设置图标
setIconImage(icon.getImage());
setResizable(false);
add("North",b);
add("Center",c);
c.button1.addActionListener(this);//7个按钮的监听
c.button22.addActionListener(this);
c.button.addActionListener(this);
c.button2.addActionListener(this);
c.button3.addActionListener(this);
b.b2.list.addActionListener(this);//双击列表人名的监听
this.setForeground(Color.black);
this.setForeground(newColor(52,133,203));
c.msg_txt.setBackground(Color.white);
b.chat_txt.setBackground(Color.white);
b.chat_txt.setForeground(Color.black);
b.chat_txt.setFont(newFont("宋体",Font.BOLD,13));
addWindowListener(newWindowAdapter()
//窗口右上角关闭按钮,直接点击也会发送登出信息
{
publicvoidwindowClosing(WindowEvente){
try{
out.writeUTF("QUIT");
}catch(IOExceptiones){
}//发给服务器
}
});
try{
socket=newSocket(host,PORT);//客户端创建socket
in=newDataInputStream(socket.getInputStream());
out=newDataOutputStream(socket.getOutputStream());
}catch(IOExceptione){
System.exit
(1);
}
say("欢迎来到姗姗聊天室");
//创建线程
if(t==null){
t=newThread(this);
//t.setPriority(Thread.MIN_PRIORITY);
t.start();//调用run方法
}
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//窗口关闭时,立即结束线程
//setResizable(true);
setVisible(true);
}
7、客户端接收的信息都是由服务器转发的,所以客户端会对服务器发来的信息进行识别处理,从而判断出信息是属于控制信息还是聊天信息,同时客户端还要对信息的头部进行处理,将一些系统标识符去掉,实现对客户的透明传输。
实现该功能的代码如下所示:
publicvoidrun(){
try{
while(true){
line=in.readUTF();
Mimasx=newMima();
if(line.startsWith("PEOPLE")){
StringlistString=line;
//这是其他用户发来的个人列表信息
if(line.endsWith("*")){
listString=line.substring(0,(line.length()-1));
}//去掉名字信息后面的*号;
b.b2.list.add(listString.substring(6))
//新人到来信息,在文件区显示
if(!
line.endsWith("*"))
{
intlast=line.indexOf("]");
Stringequalname=line.substring(6,last+1);
try{
newMP3Player();
}catch(NoPlayerExceptione){
e.printStackTrace();
}catch(MalformedURLExceptione){
e.printStackTrace();