资源描述
课程设计说明书
课程名称: Java程序设计
专 业: 班级:
设 计 人:
2015年 1月 14 日
课 程 设 计 任 务 书
一、课程设计题目: 聊天小程序
二、设计原始资料: 1、雍俊海,《Java程序设计教程》,清华大学出版社,2007;
2、耿祥义,张跃平,《Java 2 实用教程》,清华大学出版社;
3、张跃平,耿祥义,《Java 2 实验指导》,清华大学出版社;
三、设计应解决下列各主要问题:
1、用图形用户界面;(使用socket通信)
2、能实现一个聊天室中的多人聊天;
3、可以实现两个私聊;
四、设计说明书应附有下列图纸: 运行结果截图
五、小组分工说明:
六、命题发出日期: 2014.12.29 设计完成日期: 2015.1.14
指导教师评语
成绩:
指导教师(签章):
年 月 日
山东科技大学学生课程设计
目 录
1 需求分析说明 …………………………………………………………1
1.1背景…………………………………………………………1
1.2 功能要求……………………………………………………………1
1.3 运行环境……………………………………………………………1
1.4 功能实现…………………………………………………………1
2 概要设计说明…………………………………………………………2
2.1 模块调用图……………………………………………………………2
2.2 套接字连接示意图……………………………………………………2
2.3 主要函数声明…………………………………………………………2
3 详细设计说明…………………………………………………………4
3.1功能描述………………………………………………………4
3.2 主要功能详述………………………………………………………4
3.3 主要代码分析…………………………………………………………5
4 调试分析…………………………………………………………9
4.1遇到的问题……………………………………………………9
4.2 测试结果分析…………………………………………………………10
5 用户使用说明………………………………………………………10
6 课程设计总结………………………………………………………12
7 附录…………………………………………………………13
1 需求分析说明
1.1 背景
在当今的信息时代,越来越多的聊天工具被应用,Java语言是当今流行的网络编程语言,它具有面向对象、与平台无关、安全、多线程等特点。此课程设计 的题目是聊天小程序,巩固所学的Java语言基本知识,增进Java语言编辑基本功,拓宽常用类库的应用。使我们把所学课程及相关知识加以融会贯通,全面掌握Java语言的编程思想及面向对象程序设计的方法。
1.2 功能要求
1、使用图形用户界面。
2、能实现一个聊天室中多人聊天。
3、可以两人私聊。
1.3 运行环境
本程序基于Java和Eclipse开发环境,可以在一般的装有Windows系统的主机上运行。
1.4 功能实现
程序实现了聊天室的基本功能,其中有:
1、 启动服务器。
2、 进入客户端界面。
3、 登录聊天室。
4、 发送信息。
5、 关闭服务器。
6、 输入昵称。
7、 发送消息并收到其他客户的消息。
2 概要设计说明
2.1 模块调用图
2.2 套接字连接示意图
2.3 主要函数声明
1、Socket的构造方法如下:
Socket(String host,int port)
参数host是服务器的IP地址,port是一个端口号。
2、ServerSocket的构造方法如下:
ServerSocket(int port)
port是一个端口号。port必须和客户呼叫的端口号相同
3、 当建立时可能发生IOException异常,因此应像下面那样建立到服务器的套接字连接:
Try
{
Socket myscoket=new Socket(“http://192.168.0.78”,1880);
}
Catch(IOException e){}
4、 当建立服务器时可能发生IOException异常,因此,应像下面那样建立接收客户的服务器套接字:
Try
{
ServerSocket server_scoket=new ServerSocket(1880);
}
Catch(IOException e){}
比如1880端口已被占用时,就会发生IOException异常。
5、 当服务器的ServerScoket对象server_socket建立后,就可以使用accept()方法接收客户的套接字连接呼叫,代码如下:
Server_socket.accept();
6、 客户使用Socket类不带参数的构造方法Socket()创建一个套接字对象,该对象需调用
Public void connect(SocketAddress endpoint) throws IOException
请求和参数SocketAddress指定地址的套接字建立连接,为了使用connect方法,可以使用SocketAddress的子类InetSocketAddress建立一个对象,InetSocketAddress的构造方法如下:
Public InetSocketAddress(InetAddress addr,int port)
3 详细设计说明
3.1 功能描述
聊天程序分为服务器端和客户端两部分,服务端程序主要负责侦听客户端发来的消息,客户端需要登陆到服务器端才可以实现正常的聊天功能。
服务器:
1、 在特定端口上进行侦听,等待客户端连接。
2、 向已经连接到服务器端的 用户发送系统消息。
3、 当停止服务时,断开所有的用户连接。
4、 系统运行稳定、安全可靠。
客户端:
1、 连接到已经开启聊天服务的服务器端。
2、 当服务器端开启后,用户可以发表聊天信息。
3、 用户可以向所有人发送消息。
4、 系统运行稳定、安全可靠。
3.2 主要功能详述
3.2.1 客户建立连接到服务器的套接字对象
1、当套接字连接mysocket建立后,可以想象一条通信“线路”已经建立起来。mysocket可以使用getInputStream()方法获得一个输入流,然后用这个输入流读取服务器放入“线路”的信息。mysocket还可以使用getOutputStream()方法获得一个输出流,然后用这个输出流将信息写入“线路”。
2、在实际编写程序时,把mysocket使用getInputStream()方法获得的输入流接到另一个数据流上,然后就可以从这个数据流读取服务器来的信息,之所以这样是因为后面DataInputStream流有更好的从流中读取信息的方法。
3、同样把mysocket使用getOutputStream()方法得到的输出流接到另一个DataOutputStream数据流上,然后向这个数据流写入信息,发送给服务器端,之所以这样做也是因为后面的DataOutputStream流有更好的向流中写入信息的方法。
3.2.2 ServerSocket类
1、客户负责建立客户到服务器的套接字连接,即客户负责呼叫。因此服务器必须建立一个等待接收客户的套接字的ServerSocket对象。ServerSocket的构造方法如下:
ServerSocket(int port)
port是一个端口号。port必须和客户呼叫的端口号相同
2、所谓接收客户的套接字连接就是accept()方法会返回一个和客户端Socket对象相连接的Socket对象,服务器端的这个Socket对象sc使用getOutputStream()方法获得的输出流将指向客户端Socket对象myscoket使用getInputStream()方法获得的那个输入流;同样,服务器端的这个Socket对象sc使用使用的 getInputStream()方法获得的输入流将指向客户端Socket对象myscoket使用getOutputStream()方法获得的那个输出流 。
3、连接建立以后,服务器端的套接字对象调用getInetAddress()方法可以获取一个InetAddress对象,该对象含有客户端的IP地址和域名。同样,客户端的套接字对象调用getInetAddress()方法可以获取一个InetAddress对象,该对象含有服务器端的IP地址和域名。
双方通信完毕后,应使用close()方法关闭套接字连接。
3.2.3 把套接字连接放在一个线程里
需要注意的是,从套接字连接中读取数据与从文件中读取数据有很大的不同。尽管两者都是输入流,但从文件中读取数据时,所有的数据都已经在文件上了,而使用套接字连接时,可能在另一端数据发送出来之前,就已经开始试着读取了,这时,就会堵塞本线程,直到该读取方法成功读取信息,本线程才继续执行后续的操作。因此,服务器端收到一个客户的套接字后,就应该启动专门为该客户服务的线程。
3.3 主要代码分析
3.3.1 使用套接字实现的主要方法
服务器为每个客户启动一个线程,在该线程中通过套接字和客户交流信息。当向服务器发送一条聊天信息时,服务器要让所有的这些线程中的输出流写入信息,这样所有的客户的套接字的输入流就读取到了这一条信息。
如果想把信息送给特定的用户,服务器就让特定的线程中的输出流写入信息,那么只有特定的客户的套接字的输入流可以读取到这条信息。
3.3.2 客户端
public void actionPerformed(ActionEvent e)
{ if(e.getSource()==connection)//连接服务器
{ try
{ if(socket.isConnected())
{}
else
{ InetAddress address=InetAddress.getByName("127.0.0.1");//传递域名
InetSocketAddress socketAddress=new InetSocketAddress(address,666);
socket.connect(socketAddress);
in =new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
name=inputName.getText();
out.writeUTF("姓名:"+name);
send.setEnabled(true);
if(!(thread.isAlive()))
thread=new Thread(this);
thread.start();//启动线程,新建状态到就绪队列排队
}
}
catch (IOException ee){}
}
if(e.getSource()==send)//发送内容
{ String s=inputContent.getText();
if(s!=null)
{ try { out.writeUTF("聊天内容:"+name+":"+s);
}
catch(IOException e1){}
}
}
}
public void run()//线程对象调度之后所执行的操作
{ String s=null;
while(true)
{ try{ s=in.readUTF();//读取服务器发来的消息,堵塞状态
chatResult.append("\n"+s);
}
catch(IOException e)
{ chatResult.setText("与服务器已断开");
try { socket.close();
}
catch(Exception exp) {}
break;
}
}
}
}
3.3.3 服务器端
public class ChatServer
{ public static void main(String args[])
{ ServerSocket server=null;//等待接收客户的套接字的ServerSocket对象
Socket you=null;
Hashtable peopleList;
peopleList=new Hashtable();
while(true)
{ try { server=new ServerSocket(666);//端口号
}
catch(IOException e1)
{ System.out.println("正在监听");
}
try { you=server.accept();//接收客户的套接字连接呼叫
InetAddress address=you.getInetAddress();
System.out.println("客户的IP:"+address);
}
catch (IOException e) {}
if(you!=null)
{ Server_thread peopleThread=new Server_thread(you,peopleList);
peopleThread.start(); //客户线程
}
else { continue;
}
}
}
}
class Server_thread extends Thread//服务线程
{ String name=null;
Socket socket=null;
File file=null;
DataOutputStream out=null;
DataInputStream in=null;
Hashtable peopleList=null;
Server_thread(Socket t,Hashtable list)//构造
{ peopleList=list;
socket=t;
try { in=new DataInputStream(socket.getInputStream());
out=new DataOutputStream(socket.getOutputStream());
}
catch (IOException e) {}
}
4 调试分析
4.1 遇到的问题
1、 图形用户界面设计按钮和文本框设计中的按钮上的事件处理问题。
解决:通过java程序设计教程中的事件和事件处理知道了具体事件的处理是使用事件对应的监听者接口中所提供的抽象方法,这些方法需要重新定义,例如本程序中的public void actionPerformed(ActionEvent e),该方法用来对发生在按钮上事件的处理。
2、 输入流和输出流的问题。
解决:InputStreamReader缓冲处理流通信双方需要建立Socket连接,本程序中Socket包含两个流一个输出流向外发送数据,一个输入流接收数据。
3、 监听端口的问题。
解决:通过Socket应用方面的知识知道了监听端口是引用Socket构造方法,指定了服务器程序中其监听的端口,还需抛出异常。
4.2 测试结果分析
本次设计在调试过程中出现了许多问题,其中,最为严重的错误就是在最初的程序中,并没有将异常处理加入到程序中去,所以在程序运行时出现了许多错误,后来经过同学的帮助和查阅资料,我将异常处理加入到了代码中,也就没有大的问题。异常处理对程序是很重要的,加入异常处理有益于我们找到自己的错误,同时异常处理也能够将语句使用程序处理错误的能力,有效的提高了我们完成程序的效率。
5 用户使用说明
1、 首先运行服务器端,正在监听。
2、 运行客户端,输入昵称,并连接服务器,并发送消息。
3、 运行多个客户端,实现群聊。
6 课程设计总结
这次课程设计经过不懈的努力,从对整个实现的功能的设计,编写代码,还有调试分析与完善设计,经过了很长一段时间才实现了程序基本满足聊天的需要。通过这次课程设计,增强了动手能力和解决实际问题的能力,再次之前,对Java编程技术和网络Socket编程知识都只是略知皮毛,缺乏深入的认识,对其工作方式和原理缺乏透彻的认识。
在这段期间里,我认真学习了Java语言的开发、Applet小程序的实现、异常处理,对编程思想有了进一步的体会,程序虽然完成,但是还存在许多缺点,比如没有列出上线客户、界面虽然简洁但是不太美观,由于时间和掌握的知识的问题只实现了群聊,对私聊的功能没有实现,这个部分在今后我会继续完善,希望自己在不断学习和实践中收获到更多。
7 附录
//ChatServer.java
import java.io.*;
import .*;
import java.util.*;
public class ChatServer
{ public static void main(String args[])
{ ServerSocket server=null;
Socket you=null;
Hashtable peopleList;
peopleList=new Hashtable();
while(true)
{ try { server=new ServerSocket(666);
}
catch(IOException e1)
{ System.out.println("正在监听");
}
try { you=server.accept();
InetAddress address=you.getInetAddress();
System.out.println("客户的IP:"+address);
}
catch (IOException e) {}
if(you!=null)
{ Server_thread peopleThread=new Server_thread(you,peopleList);
peopleThread.start();
}
else { continue;
}
}
}
}
class Server_thread extends Thread
{ String name=null;
Socket socket=null;
File file=null;
DataOutputStream out=null;
DataInputStream in=null;
Hashtable peopleList=null;
Server_thread(Socket t,Hashtable list)
{ peopleList=list;
socket=t;
try { in=new DataInputStream(socket.getInputStream());
out=new DataOutputStream(socket.getOutputStream());
}
catch (IOException e) {}
}
public void run()
{ while(true)
{ String s=null;
try{
s=in.readUTF(); //in读取客户放进“线路”里的信息,堵塞状态
if(s.startsWith("姓名:"))
{ name=s;
boolean boo=peopleList.containsKey(name);
if(boo==false)
{ peopleList.put(name,this);
}
else
{ out.writeUTF("请换昵称:");
socket.close();
break;
}
}
else if(s.startsWith("聊天内容"))
{ String message=s.substring(s.indexOf(":")+1);
Enumeration chatPersonList=peopleList.elements();
while(chatPersonList.hasMoreElements())
{ ((Server_thread)chatPersonList.nextElement()).out.writeUTF("聊天内容:"+
message);
}
}
}
catch(IOException ee)
{ Enumeration chatPersonList=peopleList.elements();
while(chatPersonList.hasMoreElements())
{ try
{ Server_thread th=(Server_thread)chatPersonList.nextElement();
if(th!=this&&th.isAlive())
{ th.out.writeUTF("客户离线:"+name);
}
}
catch(IOException eee){}
}
peopleList.remove(name);
try { socket.close();
}
catch(IOException eee){}
System.out.println(name+"客户离开了");
break;
}
}
}
}
//Client.java
import .*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Client
{ public static void main(String args[])
{ new ChatClient();
}
}
class ChatClient extends Frame implements Runnable,ActionListener
{ Button connection,send;
TextField inputName,inputContent;
TextArea chatResult;
Socket socket=null;
DataInputStream in=null;
DataOutputStream out=null;
Thread thread;
String name="";
public ChatClient ()
{ socket=new Socket();
Box box1=Box.createHorizontalBox();
connection=new Button("Connect To Server");
send=new Button("Send");
send.setEnabled(false);
inputName=new TextField(6);
inputContent=new TextField(22);
chatResult=new TextArea();
box1.add(new Label("Input Nickname"));
box1.add(inputName);
box1.add(connection);
Box box2=Box.createHorizontalBox();
box2.add(new Label("Edit"));
box2.add(inputContent);
box2.add(send);
connection.addActionListener(this);
send.addActionListener(this);
thread=new Thread(this);
add(box1,BorderLayout.NORTH);
add(box2,BorderLayout.SOUTH);
add(chatResult,BorderLayout.CENTER);
setBounds(10,30,400,280);
setVisible(true);
validate();
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent e)
{ System.exit(0);
}
});
}
public void actionPerformed(ActionEvent e)
{ if(e.getSource()==connection)
{ try
{ if(socket.isConnected())
{}
else
{ InetAddress address=InetAddress.getByName("127.0.0.1");
InetSocketAddress socketAddress=new InetSocketAddress(address,666);
socket.connect(socketAddress);
in =new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
name=inputName.getText();
out.writeUTF("姓名:"+name);
send.setEnabled(true);
if(!(thread.isAlive()))
展开阅读全文