苏州科技大学电子信息与智能实验中心
JAVA高级程序设计 大作业
--一对多聊天程序设计
专业年级 班 级 学 号 姓 名 成 绩 任课教师
计算机科学与技术
2016年5月20日
一对多的聊天程序设计报告
1任务概述
编写一对多的聊天程序,程序由服务器和客户总原则两部分组成,服务器和客户端通过对象传送实现消息传递,两部分的交互方式如下:
(1)客户端发送命令:给服务器注册用户,服务器允许注册,则返回消息:,否则返回消息:;
(2)客户端发送命令:给服务器端进行登录,服务器如果允许登录,则返回消息:,否则返回消息:;
(3)客户端发送命令:给服务器端,服务器收到命令后返回消息:;
(4)服务器端向指定客户端发送命令:,如果meage命令中的from属性为空,则表示由服务器器发送的消息;
(5)客户端发送命令:给服务器进行注销登
-1-
录,服务器如果允许注销,则返回消息:,否则返回消息:;
请用以下方法之一实现:
(1)使用JAVA本身的序列化方法序列化命令对象;
(2)采用XML序列化命令对象;
(3)采用JSON序列化命令对象;
2 系统需求分析
(1)、该程序实现局域网内的聊天功能,包括服务器端程序和客户端程序两部分。
客户端程序:可连接到服务器,并将消息发送到服务器端和接受服务器端发送来的信息。
服务器端程序:负责发送接收和发送给客户的信息
功能如下:
连接:当客户端运行起来时客户客户端就连上了服务器端,当然首先要运行服务器,然后再运行客户端。
(2)、在客户端具备提示选项、注册、登录、聊天、退出系统主要功能。
提示选项功能:
-2-
为了明确用户做什么功能的操作而设置的提示选项模块。 注册系统功能需求:
如果选择的事注册模块,则完成用户的注册,如果注册成功,则 可以进入登录模块,系统并返回提示数据,注册失败也回返回响应的提示数据。
登陆系统功能需求:
如果选择的事登录模块,则用户进入登录功能,登录成功则向客户端返回登陆信息,同时在服务器端显示出来。建立与服务器的连接并登陆,能显示登陆错误信息。用户登陆成功,将保存其号码,以便下次登陆时,不必再输入而可以直接选择,显示登陆时间。因此必须要求后台管理系统能根据系统需求,动态的、准确的更新系统数据。
聊天管理功能需求:
如果选择的事聊天模块,则进入聊天功能。与好友聊天,实现一对一和多对多聊天;有信息提示,提示到来信息,转发给消息指定的用户。
退出功能需求:
如果选择的事退出模块或者是收到相应的退出消息,则聊天结束,服务器会发送响应的数据。
-3-
3 系统设计
我的思路是实现客户端与服务器端进行一对多的通信,这是一种最简单的聊天工具,也是对于一个初学者说是最容易理解的。但我们实际生活中的聊天模型不是这样的,例如:腾讯QQ聊天工具是把服务器作为一个中转站,一个客户端向服务器端发出请求申请连接,另一个客户端也向服务器端请求连接,一个客户端先把信息发送到服务器,然后服务器把信息转发给另一个客户端,如果把它做成和腾讯QQ差不多,那还是有一定难度的,那就必须要掌握多线程,其实多线程是一个难点。
我的思路如下:
实现客户端与服务器端的一对多通信,也就是客户端将对象发送给发送给服务器,服务器接收信息,然后服务器将回应对象发送给客户端,客户端接收, 就这样你一句我一句。你要写这个简单的聊天工具首先你首先要起一个窗口,客户端一个服务器端一个,在建立客户端与服务器的链接,运用socket和serversocket来编程,然后再对象输入输出流把客户端的信息发送给服务器端。
我建立了如下类:
-4-
主要用到的知识如下: 1) 线程
2) Java异常机制的处理
3) 网络编程中的socket和serversocket 4) 对象输入输出流 5) hashMap
4 系统实现
Command类:
public cla Command implements Serializable{ private Date sendDate;
public Date getSendDate() {
return sendDate; } public void setSendDate(Date sendDate) {
-5-
this.sendDate = sendDate; } Login类:
public cla Login extends Command { private String name; public String getName() {
return name; } public void setName(String name) {
this.name = name; } } Logout类:
public cla Logout extends Command { private String name;
public String getName() {
return name; }
public void setName(String name) {
this.name = name; }
} Meage类:
public cla Meage extends Command { private String from; private String to; private String meage; public String getFrom() {
return from; } public void setFrom(String from) {
this.from = from; } public String getTo() {
return to; } public void setTo(String to) {
this.to = to; } public String getMeage() {
return meage;
-6-
} public void setMeage(String meage) {
this.meage = meage; } Register类:
public cla Register extends Command{ private String name;
public String getName() {
return name; }
public void setName(String name) {
this.name = name; } Result类:
public cla Result extends Command{ private Command command; private String state;
public Result(Command command, String state) {
super();
this.command = command;
this.state = state; } public Command getCommand() {
return command; } public void setCommand(Command command) {
this.command = command; } public String getState() {
return state; } public void setState(String state) {
this.state = state; } Client类:
public cla Client { private static Command c; private static Result rs; public static void main(String[] args) throws Exception{
Socket socket = new Socket(\"127.0.0.1\",8888);
-7-
OutputStream os=socket.getOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(os);
InputStream reader = socket.getInputStream();
ObjectInputStream ois=new ObjectInputStream(reader);
Scanner input= new Scanner(System.in);
boolean f=true;//循环判断
String name=null;//发送方姓名
String toName=null;//接收方姓名
int temp=0;//用于定位是否是已经在聊天了
int i=0;
int logout=0; //判断是否退出
System.out.println(\"请选择:1.注册 2.登陆 3.发消息 4.退出:\");
while(f){
i=input.nextInt();
if(i==1){//注册
System.out.print(\"我是:\");
name=input.next();
Register register=new Register();
register.setName(name);
register.setSendDate(new Date());
Result result = new Result(register, \"1\");
oos.writeObject(result);
rs=(Result)ois.readObject();
System.out.println(\"服务器响应: command=\"+rs.getCommand()+ \"state=\"+rs.getState());
}else if(i==2){//登录
System.out.print(\"我是:\");
// String name=\"xu\";
name=input.next();
Login login=new Login();
login.setName(name);
// c.setSendDate(new Date());
Result result = new Result(login, \"2\");
oos.writeObject(result);
rs=(Result)ois.readObject();
System.out.println(\"服务器响应: command=\"+rs.getCommand()+ \"state=\"+rs.getState());
}else if(i==3){//聊天中...
-8-
System.out.print(\"接受方姓名:\");
toName=input.next();
System.out.print(\"我(\"+name+\")说:\");
//name=input.next();
String meage=input.next();;
Meage meage2=new Meage();
meage2.setFrom(name);
meage2.setTo(toName);
meage2.setMeage(meage);
temp=1;
if(meage.equals(\"logout\")){//如果输入logou就代表退出聊天服务器
logout=1;
}else{
// c.setSendDate(new Date());
Result result = new Result(meage2, \"3\");
oos.writeObject(result);
//读到消息
Meage m=(Meage)ois.readObject();
String str=\"我对\"+toName+ \"说:\"+m.getMeage();
System.out.println(str);
FileInformation(str,\"我\");
}
}
if(i==4||logout==1){//退出
Logout logout2=new Logout();
logout2.setName(name);
//c.setSendDate(new Date());
Result result = new Result(logout2, \"4\");
oos.writeObject(result);
rs=(Result)ois.readObject();
System.out.println(\"服务器响应: command=\"+rs.getCommand()+ \"state=\"+rs.getState());
f=false;
}
}
//System.out.println(\"欢迎再次光临!bye\");
ois.close();
oos.close();
socket.close();
-9-
} public static void FileInformation(String texts,String name ){//显示收到的文本
JFrame showInfo=new JFrame();
JPanel jp=new JPanel();
JTextArea text=new JTextArea(20,20);//文本区
text.append(texts+\"\\n\");//输入
jp.add(text);
showInfo.add(jp);
showInfo.setTitle(name+\"回答!\");
showInfo.setVisible(true);
showInfo.setSize(300,200);
showInfo.setLocation(500, 500);
showInfo.setDefaultCloseOperation(1); } }
SocketHandler类:
public cla SocketHandler implements Runnable { private Socket socket; private Result rs; private String name; ObjectOutputStream oos; Scanner input=new Scanner(System.in); public SocketHandler(Socket socket){
this.socket = socket;
} @SuppreWarnings(\"unchecked\") public void run(){
try {
InputStream reader=socket.getInputStream();
ObjectInputStream ois=new ObjectInputStream(reader);
OutputStream os=socket.getOutputStream();
oos=new ObjectOutputStream(os);
String client = \"\";
boolean f=true;
while(f){
rs= (Result) ois.readObject();
if(rs.getState().equals(\"1\"))// 注册
-10-
{
name=((Register)(rs.getCommand())).getName();
Server.users.put(name, oos);//存储写入图中
if(name.equals(\"\")){
Register register=new Register();
rs.setCommand(register);
rs.setState(\"fail\");
oos.writeObject(rs);
}else{
Register register=new Register();
rs.setCommand(register);
rs.setState(\"ok\");
oos.writeObject(rs);
}
}else if(rs.getState().equals(\"2\"))//登录
{
name=((Login)(rs.getCommand())).getName();
Server.users.put(name, oos);//存储写入图
if(name.equals(\"\")){
Login login=new Login();
rs.setCommand(login);
rs.setState(\"fail\");
oos.writeObject(rs);
}else{
Login login=new Login();
rs.setCommand(login);
rs.setState(\"ok\");
oos.writeObject(rs);
}
}
else if(rs.getState().equals(\"3\")) //用于转发 信息meage from=\"xu\" to=\"zhang\" meage=\"ddd\" />
{
//int count=0;//计数器
String toName=((Meage)(rs.getCommand())).getTo();//得到收件人的名字
String meage=((Meage)(rs.getCommand())).getMeage();//得到发送的信息
Meage meage2=new Meage();
meage2.setTo(toName);
meage2.setMeage(meage);
-11-
oos.writeObject(meage2);
oos = Server.users.get(toName);
if(oos!=null){
oos.writeObject(meage2);//向另一客户端写入信息
oos.flush();
}else{
oos.writeBytes(\"对不起!没有此用户!请检查......\");
}
} else if(rs.getState().equals(\"4\"))//退出登录//
{
name=((Logout)(rs.getCommand())).getName();
Server.users.remove(name);//删除用户名
rs.setState(\"logout\");
oos.writeObject(rs);
break;
}else{
oos.writeBytes(\"输入有误!请重新输入\");
}
oos.flush();
}
oos.close();
ois.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
} public static void FileInformation(String texts){//显示收到的文本
JFrame showInfo=new JFrame();
JPanel jp=new JPanel();
JTextArea text=new JTextArea(20,20);//文本区
text.append(texts+\"\\n\");//输入
jp.add(text);
showInfo.add(jp);
showInfo.setTitle(\"服务端相应!\");
showInfo.setVisible(true);
showInfo.setSize(300,200);
showInfo.setLocation(500, 500);
showInfo.setDefaultCloseOperation(1);
-12-
} } Server类:
public cla Server { public static HashMap users= new HashMap(); public static void main(String[] args) throws Exception{//一对多的聊天
ServerSocket server = new ServerSocket(8888);
while(true){
System.out.println(\"正在等待。。。\");
Socket socket = server.accept();
SocketHandler handler = new SocketHandler(socket);
Thread thread = new Thread(handler);
thread.start();
} } }
5 系统测试
-13-
6总结
通过本次聊天的设计,我对网络编程有了更深入的理解与认识。了解了socket编程技术,对于TCP协议有了更深入的理解。我明白了对网络通讯程序的设计的原理和过程的透彻理解,是网络通讯程序的前提。
我在代码编写的时候,使用了集成开发工具eclipse,所以编程的效率相对较高。这个聊天程序只是实现了基本的功能,而且并没有提供较为友好的图形界面。
通常,网络应用程序包含两个独立的应用程序:客户程序和服务器程序。但是,也可以设计同时完成这两种功能的程序,例如,一些服务器程序如果不能完成一个服务请求时,它将转而充当客户程序,向其它服务器程序请求信息。
通过这次的设计,我明白了很多。我知道自己在实践动手能力方面还有很大欠缺,做出能够聊天的程序增加了我对网络编程的兴趣。我也认识到了自己在编程方面的很多不足,对整个协议栈的了解还不太清晰,以后得总结一下这方面的知识。 我会更加努力,平时注重提 -14-
高自己的实践动手能力,争取更大的进步。
7 参考文献
[1] 李钟尉,陈丹丹.java项目开发案例全程实录(第2版) 2011.[2] 刘长炯.MyEclipse6 Java开发中文教程[M].北京:电子工业出版社 2007.[3] 李钟蔚.JAVA开发实战宝典[M].北京:清华大学出版社 2009 [4] 冯建华,周立柱,郝晓龙.数据库系统设计与原理.[M] .北京:清华大学出版社 2007 [5] 张海藩.软件工程导论(第5版).[M] .北京:清华大学出版社 2007 [6] 印雯.Java语言与面向对象程序设计[M].北京:清华大学出版 2000.[7] Swing ,David M.Geary.Java2图形设计[M].北京:机械工业出版社 2000.[8] 霍顿.Java2入门经典(JDK5)[M].北京: 机械工业出版社 2006.
-15-