目 录
摘要. 1
1、绪论. 1
1.1关于Java聊天室概述. 1
1.1.1选题的依据及课题的意义. 1
1.1.2开发语言的选择. 1
2、开发环境简介. 2
2.1、开发工具的选择. 2
2.2、关于JDK1.4 2
2.3、JAVA开发环境的建立. 2
3、项目概况. 3
3.1功能简介. 3
3.2套接字通信. 4
4、概要设计. 5
4.1聊天室服务器端设计。. 5
(1)图形界面的设计事件处理. 5
4.2聊天室客户端设计. 5
5、详细设计. 6
5.1服务器端的设计. 6
5.1.1服务器端的界面设计. 6
5.1.2服务器界面代码实现如下:. 7
5.1.3用户侦听设计. 15
5.2服务器端的设计. 17
5.2.1客户端的界面设计. 17
6.心得体会. 19
参考文献. 20
摘要
本系统是java基于c/s模式的聊天室程序。聊天室共分为服务器端和客户端两个部分,服务器端程序主要负责侦听客户端发来的消息,客户端需要登录到服务器端才能实现正常的聊天功能。
基于Java的聊天室是利用Eclipse开发包工具进行开发出的一款网络聊天室。这款聊天室是套接字通信开发采用c/s模式的聊天室程序。聊天室共分为服务器端和客户端两个部分,服务器端程序主要负责侦听客户端发来的消息,客户端需要登录到服务器端才能实现正常的聊天功能。
1、绪论
1.1关于Java聊天室概述
1.1.1选题的依据及课题的意义
随着网络信息时代的来临,INTERNET应用越来越广泛,人们越来越习惯于在网上获取和交流信息。据调查显示,80%以上的人上网都会打开聊天工具来聊天,而几乎每一个年轻人都会去聊天。使用网上聊天已经成为现代年轻人一种新的交往方式。
根据网上调查,在所有参加网上聊天的大学生中,进聊天室进行聊天的占69.65%,使用网络寻呼机进行聊天的占37.93%,还有2.75%的受访者声称自己使用其他方式进行聊天。进聊天室聊天是一种较为公共的聊天方式,而使用网络寻呼机则是一种具有排他性的聊天方式,一般能够用网络寻呼机进行联络的,都是比较熟悉的网友。使用网络寻呼机还意味着使用者希望自己的网友随时与自己联系,表现出一种开放性的网上交际观念。聊天室更适合于陌生人之间进行较为主观、感兴化的讨论。所以有大部分的人会进入聊天室聊天,它会给人一个完全自由的聊天世界。
作为一个信息技术专业的学生,经过几年大学知识的系统学习,应该对计算机科学与技术这个名词有了一定的认识。在这几年里,我对本专业学习也有了长足的进步,在毕业即临时,我就选择了自己感兴趣的基于API的聊天室这个课题作为我的毕业设计及论文写作,以检验几年来的学习情况。
1.1.2开发语言的选择
聊天室的发展呈现万花筒般的发展,开发工具可以是asp,php,cgi,vc++,c#,java等等,做出的聊天室各有千秋,本人以java为开发语言,对聊天室进行开发。
从下图可以看到从Java1.0发表之后,Java就被广泛地使用在桌上型应用程序以及Applet的开发上,但是,从Java1.1开始,Java又回到了它一开始的老路--也就是嵌入式系统方面的应用,在当时SunMicrosystems发表了EmbeddedJava与PersonalJava(也有人简称为PJava)这两项规格。其中EmbeddedJava是为了资源十分有限,而且没有显示设备的嵌入式装置而设计;PersonalJava则是为了在能够与网际网路连线、并拥有显示系统(例如彩色LCD)的消费性电子装置而设计。接着Java的版本演进到Java2,这时为了再明显区分各种Java的应用,所以分割出了J2EE、J2SE、以及J2ME三种版本。所有Java版本与其所依据的虚拟器所堆积起来的结构如图1.1所示。
图1.1JAVA各版本结构
2、开发环境简介
2.1、开发工具的选择
操作系统:windows 7
开发工具:
JDK1.4
Eclipse、Eclipseme插件
2.2、关于JDK1.4
JDK是Sun公司分发的免费Java开发工具,JavaSDK最早叫JavaSoftwareDevelopKit,后来改名为JDK,即JavaDevelopKit。JDK作为Java开发工具包,主要用于构建在Java平台上运行的应用程序、Applet和组件等。
2.3、JAVA开发环境的建立
为了能够编写并运行我们所编写的JAVA程序,我们需要在自己的本地机器中安装JDK开发包,JDK是内置各种JAVA开发工具,JAVA虚拟机,JAVAAPI的一个压缩包。
(1)从java.sun.com下载J2SDK,最新的版本是1.4.2_08,下载后的JDK是个执行文件,我们运行后可直接安装,缺省的安装目录是C:\j2sdk1.4.2_08。
(2)在电脑中配置环境变量,点右键打开我的电脑属性,在高级中有个环境变量,选择新建系统变量:CLASSPATH,变量值:“C:\j2sdk1.4.2_07\lib\tools.jar;C:\j2sdk1.4.2_07\lib\dt.jar;”,再新建变量名:PATH,变量值:“C:\j2sdk1.4.2_07;C:\j2sdk1.4.2_07\bin;”。具体设置如图2-3所示:
图2.1系统环境变量配置
(4)选择一个编译工具。Eclipse是一款非常优秀的开源IDE,非常适合Java开发,由于支持插件技术,受到了越来越多的开发者的欢迎。最新的Eclipse3.1不但界面做了很大的增强,而且增加了代码折叠等众多优秀功能,速度也有明显的提升。配合众多另人眼花缭乱的插件,完全可以满足从企业级Java应用到手机终端Java游戏的开发。本人选择了Eclipse作为这次毕业设计的工具,选择Eclipse作为开发的理由再简单不过了,占用资源少,JBuilder2005和SunONEStudio8.0ME建议标准内存1G以上,最低512M,目前国内个人电脑一般都达不到这个配置。同时Eclipse目前基本为国内开发Java程序的标准的IDE,使用Eclipse将使手机程序开发更加简洁。
(5)安装Eclipse插件,并进行相应的配置[5]。
3、项目概况
3.1功能简介
本系统是java基于c/s模式的聊天室程序。聊天室共分为服务器端和客户端两个部分,服务器端程序主要负责侦听客户端发来的消息,客户端需要登录到服务器端才能实现正常的聊天功能。
(1)服务器端的主要功能有:
a.在特定端口上进行侦听,等待客户端连接。
b.用户可以配置服务器的侦听端口,默认是8888。
c.可以向已经连接的客户端发送体统消息。
d.统计在线人数。
e.停止服务时,断开所有的用户连接。
(2)客户端的主要功能有:
a.连接到已经开启聊天服务的服务端。
b.用户可以配置要连接的服务器IP地址和端口号。
c.用户可以配置连接后的用户名。
d.服务器开启时,用户可以随时登录与注消。
c.用户可以想所有的人或者指定的个人发送消息。
3.2套接字通信
套接字通信(socket)是网络的基本通信单元,又称为端口,通常用来实现客户方和服务方的连接。网络上的两个程序通过双向的连接实现数据的交换,实现双方通信前链路的每一端都建立一个socket,通过对socket的读写操作实现网络的通信功能。
socket通信的过程主要有:创建socket,打开连接到socket的输入流和输出流,按照一定的协议对socket进行读写操作,关闭socket这四个步骤,通过这个四个步骤可以完成一般的socket通信。为了完成socket通信,java.net包中提供了socket和serverSocket这两个类,它们分别用来表示双向连接的客户端和服务器断,它们的构造函数有:
Socket()
通过系统默认类型的SocketImpl创建未连接套接字
Socket(InetAddressaddress,intport)
创建一个流套接字并将其连接到指定IP地址的指定端口号。
Socket(InetAddressaddress,intport,InetAddresslocalAddr,intlocalPort)
创建一个套接字并将其连接到指定远程端口上的指定远程地址。
Socket(Proxyproxy)
根据不管其他设置如何都应使用的指定代理类型(如果有),创建一个未连接的套接字。
protectedSocket(SocketImplimpl)
创建带有用户指定的SocketImpl的未连接Socket。
Socket(Stringhost,intport)
创建一个流套接字并将其连接到指定主机上的指定端口号。
Socket(Stringhost,intport,InetAddresslocalAddr,intlocalPort)
创建一个套接字并将其连接到指定远程主机上的指定远程端口。
其中端口号涉及到一个分配的问题,TCP/IP将端口号分成了两个部分,少量的作为保留端口,端口号小于256,以全局方式分配给服务进程。因此每一个标准服务器都拥有一个全局公认的端口,即使在不同的机器上其端口号也是不同的。对于常见的端口号主要有:80端口提供www服务,23提供ftp服务,110提供pop服务。剩余的为自由端口,
4、概要设计
本系统是java基于c/s模式的聊天室程序。聊天室共分为服务器端和客户端两个部分,服务器端程序主要负责侦听客户端发来的消息,客户端需要登录到服务器端才能实现正常的聊天功能。
4.1聊天室服务器端设计。
(1)图形界面的设计事件处理。
调用java.swing和java.awt包进行图形界面处理和java.swing.event与java.awt.event事件的侦听处理。
(2)实现服务器消息的收发。
分别定义向所有用户或某一个用户发送消息的方法。
(3)定义用户的管理
定义添加用户,删除用户,返回用户数目,根据用户名查找用户,根据索引查找用户。
(4)设计帮助文档
单击帮助按钮,弹出一对话框显示本系统的有关信息.
4.2聊天室客户端设计
(1)图形界面以及事件处理
调用java.swing和java.awt包进行图形界面处理和java.swing.event与java.awt.event事件的侦听处理。
(2)实现消息的收发
分别定义向所有用户或某一个用户发送消息的方法。
(3)侦听端口的修改配置
用户对所要连接的服务器IP及侦听端口进行修改配置
(4)设计帮助文档
单击帮助按钮,弹出一对话框显示本系统的有关信息.为用户提供信息帮助。
5、详细设计
5.1服务器端的设计
5.1.1服务器端的界面设计
界面设计在应用程序很重要。造就一款成功的聊天室软件,抛开其他各种因素不谈,主菜单的设计非常重要,其关键是可用性。
界面的可用性是指高效、易用、易学、易记。如果用户界面不友好,即使用户对其感兴趣,由于菜单的原因使缺乏人性化设置,用户也不会再使用这个软件。一个友好的界面是非常关键的,界面设计必须在软件设计时就进行事件添加和事件侦听和事件处理。调用serverlisten()来实现服务端用户上线和下线的侦听,调用serverReceive()来实现服务器的消息收发。
服务器端的界面如下:
图5.1服务器端界面效果
5.1.2服务器界面代码实现如下:
public class ChatClient extends JFrame implements ActionListener{
String ip = "192.168.5.72";//连接到服务端的ip地址
int port = 8888;//连接到服务端的端口号
String userName = "梅山古道";//用户名
int type = 0;//0表示未连接,1表示已连接
/**
* 程序初始化函数
*/
public void init(){
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
/**
* 事件处理
*/
public void actionPerformed(ActionEvent e) {
Object obj = e.getSource();
if (obj == userItem || obj == userButton) { //用户信息设置
//调出用户信息设置对话框
UserConf userConf = new UserConf(this,userName);
userConf.show();
userName = userConf.userInputName;
}
else if (obj == connectItem || obj == connectButton) { //连接服务端设置
//调出连接设置对话框
ConnectConf conConf = new ConnectConf(this,ip,port);
conConf.show();
ip = conConf.userInputIp;
port = conConf.userInputPort;
}
else if (obj == loginItem || obj == loginButton) { //登录
Connect();
}
else if (obj == logoffItem || obj == logoffButton) { //注销
DisConnect();
showStatus.setText("");
}
else if (obj == clientMessage || obj == clientMessageButton) { //发送消息
SendMessage();
clientMessage.setText("");
}
else if (obj == exitButton || obj == exitItem) { //退出
int j=JOptionPane.showConfirmDialog(
this,"真的要退出吗?","退出",
JOptionPane.YES_OPTION,JOptionPane.QUESTION_MESSAGE);
if (j == JOptionPane.YES_OPTION){
if(type == 1){
DisConnect();
}
System.exit(0);
} }
else if (obj == helpItem) { //菜单栏中的帮助
//调出帮助对话框
Help helpDialog = new Help(this);
helpDialog.show();
} }
public void Connect(){
try{
socket = new Socket(ip,port);
}
catch (Exception e){
JOptionPane.showConfirmDialog(
this,"不能连接到指定的服务器。\n请确认连接设置是否正确。","提示",
JOptionPane.DEFAULT_OPTION,JOptionPane.WARNING_MESSAGE);
return;
}
try{
output = new ObjectOutputStream(socket.getOutputStream());
output.flush();
input = new ObjectInputStream(socket.getInputStream() );
output.writeObject(userName);
output.flush();
recvThread = new ClientReceive(socket,output,input,combobox,messageShow,showStatus);
recvThread.start();
loginButton.setEnabled(false);
loginItem.setEnabled(false);
userButton.setEnabled(false);
userItem.setEnabled(false);
connectButton.setEnabled(false);
connectItem.setEnabled(false);
logoffButton.setEnabled(true);
logoffItem.setEnabled(true);
clientMessage.setEnabled(true);
messageShow.append("连接服务器 "+ip+":"+port+" 成功...\n");
type = 1;//标志位设为已连接
}
catch (Exception e){
System.out.println(e);
return;
}
}
public void DisConnect(){
loginButton.setEnabled(true);
loginItem.setEnabled(true);
userButton.setEnabled(true);
userItem.setEnabled(true);
connectButton.setEnabled(true);
connectItem.setEnabled(true);
logoffButton.setEnabled(false);
logoffItem.setEnabled(false);
clientMessage.setEnabled(false);
if(socket.isClosed()){
return ;
}
try{
output.writeObject("用户下线");
output.flush();
input.close();
output.close();
socket.close();
messageShow.append("已经与服务器断开连接...\n");
type = 0;//标志位设为未连接
}
catch (Exception e){
//
}
}
//发送信息
public void SendMessage(){
String toSomebody = combobox.getSelectedItem().toString();
String status = "";
if(checkbox.isSelected()){
status = "悄悄话";
}
String action = actionlist.getSelectedItem().toString();
String message = clientMessage.getText();
if(socket.isClosed()){
return ;
}
try{
output.writeObject("聊天信息");
output.flush();
output.writeObject(toSomebody);
output.flush();
output.writeObject(status);
output.flush();
output.writeObject(action);
output.flush();
output.writeObject(message);
output.flush();
}
catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
ChatClient app = new ChatClient();
}
}
5.1.2实现服务器消息的收发。
分别定义向所有用户或某一个用户发送消息的方法。
其实现代码如下:
package ChatServer;
import javax.swing.*;
import java.io.*;
import java.net.*;
/*
* @author lijie
*
* 服务器收发消息的类
*/
public class ServerReceive extends Thread {
JTextArea textarea;
JTextField textfield;
JComboBox combobox;
Node client;
UserLinkList userLinkList;//用户链表
public boolean isStop;
public ServerReceive(JTextArea textarea,JTextField textfield,
JComboBox combobox,Node client,UserLinkList userLinkList){
this.textarea = textarea;
this.textfield = textfield;
this.client = client;
this.userLinkList = userLinkList;
this.combobox = combobox;
isStop = false;
}
public void run(){
//向所有人发送用户的列表
sendUserList();
while(!isStop && !client.socket.isClosed()){
try{
String type = (String)client.input.readObject();
if(type.equalsIgnoreCase("聊天信息")){
String toSomebody = (String)client.input.readObject();
String status = (String)client.input.readObject();
String action = (String)client.input.readObject();
String message = (String)client.input.readObject();
String msg = client.username
+" "+ action
+ "对 "
+ toSomebody
+ " 说 : "
+ message
+ "\n";
if(status.equalsIgnoreCase("悄悄话")){
msg = " [悄悄话] " + msg;
}
textarea.append(msg);
if(toSomebody.equalsIgnoreCase("所有人")){
sendToAll(msg);
//向所有人发送消息
}
else{
try{
client.output.writeObject("聊天信息");
client.output.flush();
client.output.writeObject(msg);
client.output.flush();
}
catch (Exception e){
System.out.println("###"+e);
}
Node node = userLinkList.findUser(toSomebody);
if(node != null){
node.output.writeObject("聊天信息");
node.output.flush();
node.output.writeObject(msg);
node.output.flush();
}
}
}
else if(type.equalsIgnoreCase("用户下线")){
Node node = userLinkList.findUser(client.username);
userLinkList.delUser(node);
String msg = "用户 " + client.username + " 下线\n";
int count = userLinkList.getCount();
combobox.removeAllItems();
combobox.addItem("所有人");
int i = 0;
while(i < count){
node = userLinkList.findUser(i);
if(node == null) {
i ++;
continue;
}
combobox.addItem(node.username);
i++;
}
combobox.setSelectedIndex(0);
textarea.append(msg);
textfield.setText("在线用户" + userLinkList.getCount() + "人5.22实现服务器消息的收发。\n");
sendToAll(msg);//向所有人发送消息
sendUserList();//重新发送用户列表,刷新
break;
}
}
catch (Exception e){
//System.out.println(e);
}
}
}
/*
* 向所有人发送消息
*/
public void sendToAll(String msg){
int count = userLinkList.getCount();
int i = 0;
while(i < count){
Node node = userLinkList.findUser(i);
if(node == null) {
i ++;
continue;
}
try{
node.output.writeObject("聊天信息");
node.output.flush();
node.output.writeObject(msg);
node.output.flush();
}
catch (Exception e){
//System.out.println(e);
}
i++;
}
}
/*
* 向所有人发送用户的列表
*/
public void sendUserList(){
String userlist = "";
int count = userLinkList.getCount();
int i = 0;
while(i < count){
Node node = userLinkList.findUser(i);
if(node == null) {
i ++;
continue;
}
userlist += node.username;
userlist += '\n';
i++;
}
i = 0;
while(i < count){
Node node = userLinkList.findUser(i);
if(node == null) {
i ++;
continue;
}
try{
node.output.writeObject("用户列表");
node.output.flush();
node.output.writeObject(userlist);
node.output.flush();
}
catch (Exception e){
e.printStackTrace();
}
i++;
}
}
}
5.1.3用户侦听设计
主函数调用该方法用于侦听用户的上线与下线,但必须调用userLinklist()来实现那的,用户在线情况发生变换时,该类会对主类的界面进行修改。
实现代码如下:
public class ServerListen extends Thread {
ServerSocket server;
JComboBox combobox;
JTextArea textarea;
JTextField textfield;
UserLinkList userLinkList;//用户链表
Node client;
ServerReceive recvThread;
public boolean isStop;
/*
* 聊天服务端的用户上线于下线侦听类
*/
public ServerListen(ServerSocket server,JComboBox combobox,
JTextArea textarea,JTextField textfield,UserLinkList userLinkList){
this.server = server;
this.combobox = combobox;
this.textarea = textarea;
this.textfield = textfield;
this.userLinkList = userLinkList;
isStop = false;
}
public void run(){
while(!isStop && !server.isClosed()){
try{
client = new Node();
client.socket = server.accept();
client.output = new ObjectOutputStream(client.socket.getOutputStream());
client.output.flush();
client.input = new ObjectInputStream(client.socket.getInputStream());
client.username = (String)client.input.readObject();
//显示提示信息
combobox.addItem(client.username);
userLinkList.addUser(client);
textarea.append("用户 " + client.username + " 上线" + "\n");
textfield.setText("在线用户" + userLinkList.getCount() + "人\n");
recvThread = new ServerReceive(textarea,textfield,
combobox,client,userLinkList);
recvThread.start();
}
catch(Exception e){
}
}
}
}
5.2服务器端的设计
5.2.1客户端的界面设计
该界面的设计于服务器端的效果很相同,代码的实现也非常的雷同在这里代码的就没有进行累赘的描述。
界面效果图如下:
图5.2客户端界面效果图
图5.3两个人私聊
图5.4多人聊天
6.心得体会
这次课程设计介绍了整个聊天室开发的详细设计过程,包括了算法的实现,并对比较重要的函数作了详细分析。
本次设计已经是我大学中最后一次对专业知识的综合实践活动,同时也是我所做工作量最大的一次作业,因此从一开始我对本次毕业设计就给予了高度的重视。从选题,收集,资料,学习相关技术到实现编程,我都一丝不苟的对待。
经过几个星期的努力,我终于完成了这个基于java的聊天室。在设计过程中,我遇到了很多的难题,在解决这些问题的同时,我也加深了对Java语言的了解,特别是套节字通信部分,也学会了解决问题的方法。我制作的这个聊天室基本完成了设计要求的功能,基本实现了单人发送信息和多个人发送信息的功能,虽然本聊天室有这样那样的不足,但是通过这次设计,我的综合能力和知识都得到了很大提高。我对java语言的开发也产生了浓厚的兴趣,在以后的学习以及联系的过程中,我会更加努力地学习好Java这门语言。
参考文献
[1] 邹建峰JAVA2核心技术.机械工业出版社[M], 2005, 1-1.
[2] Bruce Eckel[美.JAVA2编程思想[M]. 侯捷 译.机械工业出版社,2005,1-1.
[3] 黄聪明.精通JAVA2程序设计[J].清华大学出版社,2004,3-4.
[4] Addison Wesley[美].The Java Programming Language[M].电子文档,2006, 1-1.