这是我用java socket写的一个简单的聊天室程序,以下是我的设计文档和源代码:
ChatRoom 聊天室设计文档
客户端和服务器界面:
客户端
服务器端
ChatRoom 聊天室程序功能简介:
服务器接受每个连接客户发来的信息,再广播给每个客户。
Server:
服务器 ChatRoomServer 启动后自动监听默认端口:DEFAULT_PORT 6666等待客户的连接,当有客户连接上来时,在文本域显示连接信息。
服务器端点击窗口关闭或点击窗体内的退出按钮可以关闭服务器。
Client:
客户端ChatRoomClient 启动后显示客户端界面:窗体上方有一个“连接”按钮和一个文本筐(文本筐在按钮的右面)。在文本筐中输入服务器地址,再按左边的“连接”按钮或按键盘上的”Enter”键,连接服务器。如果连接成功将显示连接成功信息,否则将显示连接失败信息。
连接成功后客户可以在窗体底部消息标签右边的文本筐中输入要发送的消息,然后点击文本筐右边的“发送“按钮或按键盘上的”Enter“键发送信息。
客户端受到的信息将显示在窗体中部的文本域中。
ChatRoomServer.java——说明:
//由于在程序中做了较多注释,所以这里只做简单的叙述:
1.程序启动是初始化界面、并开始监听:
public ChatRoomServer(){
try{
jbInit();
}catch(Exception e){
e.printStackTrace();
}
serverListen();//服务器开始监听
}
jbInit(){ 、、、、}初始化界面,注册button1(退出)按钮和窗口关闭事件。
serverListen(){ 、、、}打开并监听端口:6666,
2.public void run(){//接受连接并记录线程信息
、、、、、、
try{
while(true){
Socket clientSock=serverSock.accept();
CommunicateThread ct=new CommunicateThread(clientSock,this,index);//创建线程保持连接
clients.add(ct);//记录连接信息到clients数组
clientsInfor.add("Thread-"+i);//记录连接名称
、、、、、、、、、
}
CommunicateThread ct=new CommunicateThread(clientSock,this,index);
当有连接上来时,创建线程以保持连接。
3.public void exit(){ 、、、}
退出并关闭seversock
4.class CommunicateThread extends Thread{ 、、、、}//保持连接线程
5. class BroadcastThread extends Thread{ 、、、}//广播线程
6.//处理窗口关闭事件的适配器
class ChatFrame_WindowAdapter extends java.awt.event.WindowAdapter{ 、、、}
ChatRoomClient.java——说明:
1. 初始化窗体
public ChatRoomClient(){
try{
jbInit();
}catch(Exception e){
e.printStackTrace();
}
}
jbInit(){ 、、、、}初始化窗体,将button1(连接)、button2(发送)注册到ActionListener,将textField1(服务器地址) 、textField2(消息)注册到keyListener,将窗体注册到WindowListener。
2. StartConnect(){ 、、、、}//连接服务器
点击button1或在textField1中按“Enter”键后调用startConnect()连接服务器并启动线程run(),读取服务器广播来的信息,打印到文本区域。
3.public void exit(){ 、、、}//窗口关闭;如果有连接则关闭连接和相关的"流"
4.//文本筐textField1的键击事件适配器
class textField1_KeyAdapter extends java.awt.event.KeyAdapter{}
5.//文本筐textField2的键击事件适配器
class textField2_KeyAdapter extends java.awt.event.KeyAdapter{}
6.//窗口关闭事件适配器
class ChatFrame_WindowAdapter extends java.awt.event.WindowAdapter{}
聊天室服务器端源程序:
package chatserver2;
//Chat Room Server//this software is designed by Chen Heping(陈和平)import java.awt.*;
import java.awt.event.*;import java.io.*;import java.net.*;public class ChatRoomServer extends Frame implements Runnable{
Panel panel; ScrollPane sPanel; TextArea textArea; Button button1; //net ServerSocket serverSock; public final static int DEFAULT_PORT=6666;//默认端口号 Thread chatAcceptThread;//启动接受连接的线程 BroadcastThread broadcastThread;//广播thread; run when server is listening java.util.Vector clients;//记录连接的线程 java.util.Vector clientsInfor;//记录连接线程的信息 public static int index=0; public ChatRoomServer(){ try{ jbInit(); }catch(Exception e){ e.printStackTrace(); } serverListen();//服务器开始监听 } private void jbInit(){//初始化界面 panel=new Panel(); sPanel=new ScrollPane(); textArea=new TextArea("server information:\n"); button1=new Button("退出"); sPanel.add(textArea); button1.addActionListener(new java.awt.event.ActionListener(){//退出按钮注册 public void actionPerformed(ActionEvent e){ button1_actionPerformed(e); } }); panel.add(button1); this.addWindowListener(new ChatFrame_WindowAdapter(this));//注册到继承了窗口适配器的类 this.setSize(600,600); this.setLayout(new BorderLayout()); this.add(sPanel,BorderLayout.CENTER); this.add(panel,BorderLayout.SOUTH); this.show(); } private void button1_actionPerformed(ActionEvent e){ exit(); } public void processMsg(String str){// textArea.append(str); } private void serverListen(){ try{ serverSock=new ServerSocket(DEFAULT_PORT); }catch(IOException e){ processMsg(e.toString()); processMsg("server failed!\n"); } processMsg("server listening on port:"+DEFAULT_PORT); clients=new java.util.Vector(); clientsInfor=new java.util.Vector(); chatAcceptThread=new Thread(this);//启动接受连接的线程 chatAcceptThread.start(); broadcastThread=new BroadcastThread(this);//广播线程 broadcastThread.start(); //还有一个回收无用连接thread 的线程 } public void run(){//接受连接并记录线程信息 int i=0; try{ while(true){ Socket clientSock=serverSock.accept(); CommunicateThread ct=new CommunicateThread(clientSock,this,index);//创建线程保持连接 clients.add(ct);//record Communicate Thread; i++; index++;//version2 clientsInfor.add("Thread-"+i); processMsg("Thread-"+i+"join in\n"); } }catch(IOException e){ processMsg(e.toString()); } } public void exit(){ broadcastThread.broadcast("Server exit!"); try{ serverSock.close(); }catch(IOException ioe){} finally{ System.exit(0); } } public static void main(String[] args){ ChatRoomServer chat=new ChatRoomServer(); }}class CommunicateThread extends Thread{//保持连接线程
protected Socket clientSock; protected BufferedReader in=null; protected PrintWriter out; ChatRoomServer chatFrame; boolean isTrue=true;//run() java.util.Vector inforStack; int index2;// public CommunicateThread(Socket Sock,ChatRoomServer cFrame,int index){ clientSock=Sock; chatFrame=cFrame; index2=index; inforStack=new java.util.Vector(); try{ in=new BufferedReader(new InputStreamReader(clientSock.getInputStream())); out=new PrintWriter(clientSock.getOutputStream()); }catch(IOException ei){ try{ clientSock.close(); }catch(IOException ei2){ } chatFrame.processMsg(ei.toString()); return; } this.start(); } public void run(){ String infor; try{ while(isTrue){ infor=in.readLine(); if(infor.equals("Client exit!")){ writeInformation(infor);//把信息写到信息栈,以倍广播出去 stopRun(); }else if(infor!=null){ writeInformation(infor); }//else break; try{ Thread.sleep(100);//version2 }catch(InterruptedException ex){} } }catch(IOException e){ ;} finally{ try{ in.close(); out.close(); clientSock.close(); chatFrame.clients.remove(index2);//在clients中清除本线程序 ChatRoomServer.index--;// }catch(IOException ei){;} } } public void writeInformation(String infor){//写信息栈 inforStack.add(infor); } private void stopRun(){//终止线程 isTrue=false; } public void sendInformation(String str){//发送信息 try{ out.println(str); out.flush(); }catch(Exception e){;} } }class BroadcastThread extends Thread{//广播线程
ChatRoomServer chatFrame2; java.util.Vector chatClients;//连接线程信息 java.util.Vector msgStack;//信息栈 java.util.Vector clientMsg;//记录客户发送的信息 CommunicateThread comThread1; CommunicateThread comThread2; String string;//information in inforStack String clientName;//client thread name String broadcastInfor;//broadcast information=clientName+string; public BroadcastThread(ChatRoomServer cFrame){ chatFrame2=cFrame; chatClients=chatFrame2.clients; clientMsg=chatFrame2.clientsInfor; //this.start(); } public void broadcast(String str){//广播 for(int k=0;k<chatClients.size();k++){//send to everyone分别调用每个连接线程,发送信息 comThread2=(CommunicateThread)chatClients.get(k); comThread2.sendInformation(str); } } public void run(){ try{ while(true){ for(int i=0;i<chatClients.size();i++){ comThread1=(CommunicateThread)chatClients.get(i); msgStack=comThread1.inforStack;//得到每个连接的信息栈 clientName=(String)clientMsg.get(i);//客户名 //读取每个连接线程的信息栈并把信息发送出去 for(int j=0;j<msgStack.size();j++){ string=(String)msgStack.get(j); broadcastInfor=clientName+"->"+string; broadcast(broadcastInfor); } //clear the inforStack msgStack.removeAllElements();//清除以发送的信息 } try{ Thread.sleep(100);//version2 }catch(InterruptedException ex){} } }catch(Exception e){} } }//处理窗口关闭事件的适配器
class ChatFrame_WindowAdapter extends java.awt.event.WindowAdapter{ ChatRoomServer chatFrame; public ChatFrame_WindowAdapter(ChatRoomServer chatFrame){ this.chatFrame=chatFrame; } public void windowClosing(WindowEvent e){//exit program chatFrame.exit();//reference to the method exit() in ChatRoomServer. }}
聊天室客户端源程序:
package chatclient_test;
//ChatRoomClient//designed by Chen Heping(陈和平)import java.awt.*;
import java.awt.event.*;import java.io.*;import java.net.*;public class ChatRoomClient extends Frame implements Runnable{
Panel panel1,panel2; Button button1,button2; TextField textField1,textField2; Label label1; TextArea textArea; ScrollPane sPanel; //net PrintWriter out; BufferedReader in=null; Socket sock; public final static int DEFAULT_PORT=6666; //create Thread to Read information from Server Thread readThread; boolean isTrue=true;//thread can go on runing ?? public ChatRoomClient(){ try{ jbInit(); }catch(Exception e){ e.printStackTrace(); } } public static void main(String[] args){//main method ChatRoomClient c=new ChatRoomClient(); c.show(); } private void jbInit(){//should set size,position and Font of every component button1=new Button("连接");// set Font button2=new Button("发送"); textField1=new TextField("input Server address here!"); textField2=new TextField("input Message here and send to server"); label1=new Label("消息:"); panel1=new Panel(); panel2=new Panel(); sPanel=new ScrollPane(); textArea=new TextArea(); //panel1 //press button1: 连接 to connect the client to server button1.addActionListener(new java.awt.event.ActionListener(){ public void actionPerformed(ActionEvent e){ button1_actionPerformed(e); } }); //textField1:for input the address of server;be registered to KeyListener. //press key:Enter to connect the client to server textField1.addKeyListener(new textField1_KeyAdapter(this));//java.awt.event.KeyAdapter() panel1.add(button1); panel1.add(textField1); //sPanel ScrollPane sPanel.add(textArea); //panel2 //press button2: 发送 to send message button2.addActionListener(new java.awt.event.ActionListener(){ public void actionPerformed(ActionEvent e){ button2_actionPerformed(e); } }); //textField2:for input message;be registered to KeyListener. //press key:Enter to send message textField2.addKeyListener(new textField2_KeyAdapter(this)); panel2.add(label1); panel2.add(textField2); panel2.add(button2); //frame this.addWindowListener(new ChatFrame_WindowAdapter(this));//frame is registered to WindowListener this.setLayout(new BorderLayout()); this.setSize(500,400); this.add(panel1,BorderLayout.NORTH); this.add(sPanel,BorderLayout.CENTER); this.add(panel2,BorderLayout.SOUTH); //this.show() } public void startConnect(){//开始连接 try{ sock=new Socket(textField1.getText(),DEFAULT_PORT); if(sock!=null){//connection successed processMsg("Connect successfully!"); } in=new BufferedReader(new InputStreamReader(sock.getInputStream())); out=new PrintWriter(sock.getOutputStream()); }catch(IOException ex){ processMsg(ex.toString()); processMsg("Connect failed!"); } readThread=new Thread(this); readThread.start(); } //public void endConnect(){//close IOstream public void sendInformation(){ out.println(textField2.getText()); out.flush(); } private void button1_actionPerformed(ActionEvent e){//连接按钮 startConnect(); } private void button2_actionPerformed(ActionEvent e){//发送按钮 sendInformation(); } public void stopRun(){//to stop the running thread isTrue=false; } public void processMsg(String msg){//客户端处理消息 textArea.append(msg); textArea.append("\n"); } public void run(){ String msg; isTrue=true; while(isTrue){ try{ msg=in.readLine(); if(msg.equals("Server exit!")){//server exit processMsg(msg); stopRun();//终止线程 }else if(msg!=null){ processMsg(msg); } Thread.sleep(1000); }catch(IOException e){ processMsg(e.toString()); }catch(InterruptedException ei){ processMsg(ei.toString()); } } //endConnect(); try{//服务器退出关闭连接和相关的"流" sock.close(); in.close(); out.close(); }catch(IOException ioe){} } public void exit(){//窗口关闭;如果有连接则关闭连接和相关的"流" try{//send "Client exit!" to Server! out.println("Client exit!"); out.flush(); }catch(Exception exc){} //endConnect(); try{//close IOstream sock.close(); in.close(); out.close(); }catch(IOException ioe){} finally{ System.exit(0); } }}//文本筐textField1的键击事件适配器
class textField1_KeyAdapter extends java.awt.event.KeyAdapter{ ChatRoomClient chatFrame; public textField1_KeyAdapter(ChatRoomClient chatFrame){ this.chatFrame=chatFrame; } public void keyPressed(KeyEvent e){//输入的是enter,开始连接! int j=e.getKeyCode(); if(j==e.VK_ENTER){ chatFrame.startConnect(); } }}//文本筐textField2的键击事件适配器
class textField2_KeyAdapter extends java.awt.event.KeyAdapter{ ChatRoomClient chatFrame; public textField2_KeyAdapter(ChatRoomClient chatFrame){ this.chatFrame=chatFrame; } public void keyPressed(KeyEvent e){//键击Enter键,发送信息! int j=e.getKeyCode(); if(j==e.VK_ENTER){ chatFrame.sendInformation(); } }}//窗口关闭事件适配器
class ChatFrame_WindowAdapter extends java.awt.event.WindowAdapter{ ChatRoomClient chatFrame; public ChatFrame_WindowAdapter(ChatRoomClient chatFrame){ this.chatFrame=chatFrame; } public void windowClosing(WindowEvent e){//exit program chatFrame.exit();//reference to the method exit() in ChatRoomClient. }}