当前位置:文档之家› JavaSocket实现多人聊天室

JavaSocket实现多人聊天室

Java Socket实现多人聊天室---swing做UI标签:socket聊天javaexception服务器string2011-08-31 15:0620679人阅读评论(25)收藏举报分类:java(21)版权声明:本文为博主原创文章,未经博主允许不得转载。

今天翻硬盘的workspace发现一个Java Socket实现多人聊天室的源码,不记得是什么时候的事情了,貌似不是我写的。

但写得还不错,至少算个有模有样的聊天室工具。

我简单的修改了一下,拿出来跟大家分享一下,仅供参考。

界面是用swing写的,还不懒,简约大方。

有图有真相:正如上图所示,这个程序分为服务器端和客户端,说白了就是两个main class,用eclipse 直接运行之。

聊天室的设计思想是:在局域网下,利用socket进行连接通信,当服务器端启动的时候,利用Thread线程不停的等待客户端的链接;当有客户端开启连接的时候,服务器端通过IO流反馈“上线用户”信息给客户端,客户端也使用线程不停的接收服务器的信息,从而实现多人在线聊天功能。

程序中有三个类,分别Server.java(服务器端)、Client(客户端)、User.java(javabean)。

代码如下:Server.java(服务器端):[html]view plaincopy1.import java.awt.BorderLayout;2.import java.awt.Color;3.import java.awt.GridLayout;4.import java.awt.Toolkit;5.import java.awt.event.ActionEvent;6.import java.awt.event.ActionListener;7.import java.awt.event.WindowAdapter;8.import java.awt.event.WindowEvent;9.import java.io.BufferedReader;10.import java.io.IOException;11.import java.io.InputStreamReader;12.import java.io.PrintWriter;13.import .BindException;14.import .ServerSocket;15.import .Socket;16.import java.util.ArrayList;17.import java.util.StringTokenizer;18.19.import javax.swing.DefaultListModel;20.import javax.swing.JButton;21.import javax.swing.JFrame;22.import javax.swing.JLabel;23.import javax.swing.JList;24.import javax.swing.JOptionPane;25.import javax.swing.JPanel;26.import javax.swing.JScrollPane;27.import javax.swing.JSplitPane;28.import javax.swing.JTextArea;29.import javax.swing.JTextField;30.import javax.swing.border.TitledBorder;31.32.public class Server{33.34.private JFrame frame;35.private JTextArea contentArea;36.private JTextField txt_message;37.private JTextField txt_max;38.private JTextField txt_port;39.private JButton btn_start;40.private JButton btn_stop;41.private JButton btn_send;42.private JPanel northPanel;43.private JPanel southPanel;44.private JScrollPane rightPanel;45.private JScrollPane leftPanel;46.private JSplitPane centerSplit;47.private JList userList;48.private DefaultListModel listModel;49.50.private ServerSocket serverSocket;51.private ServerThread serverThread;52.private ArrayList<ClientThread>clients;53.54.private boolean isStart=false;55.56.//主方法,程序执行入口57.public static void main(String[]args){58.new Server();59.}60.61.//执行消息发送62.public void send(){63.if(!isStart){64.JOptionPane.showMessageDialog(frame,"服务器还未启动,不能发送消息!","错误",65.JOptionPane.ERROR_MESSAGE);66.return;67.}68.if(clients.size()==0){69.JOptionPane.showMessageDialog(frame,"没有用户在线,不能发送消息!","错误",70.JOptionPane.ERROR_MESSAGE);71.return;72.}73.String message=txt_message.getText().trim();74.if(message==null||message.equals("")){75.JOptionPane.showMessageDialog(frame,"消息不能为空!","错误",76.JOptionPane.ERROR_MESSAGE);77.return;78.}79.sendServerMessage(message);//群发服务器消息80.contentArea.append("服务器说:"+txt_message.getText()+"\r\n");81.txt_message.setText(null);82.}83.84.//构造放法85.public Server(){86.frame=new JFrame("服务器");87.//更改JFrame的图标:88.//frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png")));89.frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Server.class.getResource("qq.png")));90.contentArea=new JTextArea();91.contentArea.setEditable(false);92.contentArea.setForeground(Color.blue);93.txt_message=new JTextField();94.txt_max=new JTextField("30");95.txt_port=new JTextField("6666");96.btn_start=new JButton("启动");97.btn_stop=new JButton("停止");98.btn_send=new JButton("发送");99.btn_stop.setEnabled(false);100.listModel=new DefaultListModel();erList=new JList(listModel);102.103.southPanel=new JPanel(new BorderLayout());104.southPanel.setBorder(new TitledBorder("写消息"));105.southPanel.add(txt_message,"Center");106.southPanel.add(btn_send,"East");107.leftPanel=new JScrollPane(userList);108.leftPanel.setBorder(new TitledBorder("在线用户"));109.110.rightPanel=new JScrollPane(contentArea);111.rightPanel.setBorder(new TitledBorder("消息显示区"));112.113.centerSplit=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,left Panel,114.rightPanel);115.centerSplit.setDividerLocation(100);116.northPanel=new JPanel();117.northPanel.setLayout(new GridLayout(1,6));118.northPanel.add(new JLabel("人数上限"));119.northPanel.add(txt_max);120.northPanel.add(new JLabel("端口"));121.northPanel.add(txt_port);122.northPanel.add(btn_start);123.northPanel.add(btn_stop);124.northPanel.setBorder(new TitledBorder("配置信息"));125.126.frame.setLayout(new BorderLayout());127.frame.add(northPanel,"North");128.frame.add(centerSplit,"Center");129.frame.add(southPanel,"South");130.frame.setSize(600,400);131.//frame.setSize(Toolkit.getDefaultToolkit().getScreenSize());//设置全屏132.int screen_width=Toolkit.getDefaultToolkit().getScreenSize().wid th;133.int screen_height=Toolkit.getDefaultToolkit().getScreenSize().hei ght;134.frame.setLocation((screen_width-frame.getWidth())/2,135.(screen_height-frame.getHeight())/2);136.frame.setVisible(true);137.138.//关闭窗口时事件139.frame.addWindowListener(new WindowAdapter(){140.public void windowClosing(WindowEvent e){141.if(isStart){142.closeServer();//关闭服务器143.}144.System.exit(0);//退出程序145.}146.});147.148.//文本框按回车键时事件149.txt_message.addActionListener(new ActionListener(){150.public void actionPerformed(ActionEvent e){151.send();152.}153.});154.155.//单击发送按钮时事件156.btn_send.addActionListener(new ActionListener(){157.public void actionPerformed(ActionEvent arg0){158.send();159.}160.});161.162.//单击启动服务器按钮时事件163.btn_start.addActionListener(new ActionListener(){164.public void actionPerformed(ActionEvent e){165.if(isStart){166.JOptionPane.showMessageDialog(frame,"服务器已处于启动状态,不要重复启动!",167."错误",JOptionPane.ERROR_MESSAGE);168.return;169.}170.int max;171.int port;172.try{173.try{174.max=Integer.parseInt(txt_max.getText()); 175.}catch(Exception e1){176.throw new Exception("人数上限为正整数!");177.}178.if(max<=0){179.throw new Exception("人数上限为正整数!");180.}181.try{182.port=Integer.parseInt(txt_port.getText()); 183.}catch(Exception e1){184.throw new Exception("端口号为正整数!"); 185.}186.if(port<=0){187.throw new Exception("端口号为正整数!"); 188.}189.serverStart(max,port);190.contentArea.append("服务器已成功启动!人数上限:"+max+",端口:"+port191.+"\r\n");192.JOptionPane.showMessageDialog(frame,"服务器成功启动!");193.btn_start.setEnabled(false);194.txt_max.setEnabled(false);195.txt_port.setEnabled(false);196.btn_stop.setEnabled(true);197.}catch(Exception exc){198.JOptionPane.showMessageDialog(frame,exc.getMe ssage(),199."错误",JOptionPane.ERROR_MESSAGE);200.}201.}202.});203.204.//单击停止服务器按钮时事件205.btn_stop.addActionListener(new ActionListener(){206.public void actionPerformed(ActionEvent e){207.if(!isStart){208.JOptionPane.showMessageDialog(frame,"服务器还未启动,无需停止!","错误",209.JOptionPane.ERROR_MESSAGE); 210.return;211.}212.try{213.closeServer();214.btn_start.setEnabled(true);215.txt_max.setEnabled(true);216.txt_port.setEnabled(true);217.btn_stop.setEnabled(false);218.contentArea.append("服务器成功停止!\r\n");219.JOptionPane.showMessageDialog(frame,"服务器成功停止!");220.}catch(Exception exc){221.JOptionPane.showMessageDialog(frame,"停止服务器发生异常!","错误",222.JOptionPane.ERROR_MESSAGE);223.}224.}225.});226.}227.228.//启动服务器229.public void serverStart(int max,int port)throws .BindExcepti on{230.try{231.clients=new ArrayList<ClientThread>();232.serverSocket=new ServerSocket(port);233.serverThread=new ServerThread(serverSocket,max); 234.serverThread.start();235.isStart=true;236.}catch(BindException e){237.isStart=false;238.throw new BindException("端口号已被占用,请换一个!"); 239.}catch(Exception e1){240.e1.printStackTrace();241.isStart=false;242.throw new BindException("启动服务器异常!");243.}244.}245.246.//关闭服务器247.@SuppressWarnings("deprecation")248.public void closeServer(){249.try{250.if(serverThread!=null)251.serverThread.stop();//停止服务器线程252.253.for(int i=clients.size()-1;i>=0;i--){254.//给所有在线用户发送关闭命令255.clients.get(i).getWriter().println("CLOSE");256.clients.get(i).getWriter().flush();257.//释放资源258.clients.get(i).stop();//停止此条为客户端服务的线程259.clients.get(i).reader.close();260.clients.get(i).writer.close();261.clients.get(i).socket.close();262.clients.remove(i);263.}264.if(serverSocket!=null){265.serverSocket.close();//关闭服务器端连接266.}267.listModel.removeAllElements();//清空用户列表268.isStart=false;269.}catch(IOException e){270. e.printStackTrace();271.isStart=true;272.}273.}274.275.//群发服务器消息276.public void sendServerMessage(String message){277.for(int i=clients.size()-1;i>=0;i--){278.clients.get(i).getWriter().println("服务器:"+message+"(多人发送)");279.clients.get(i).getWriter().flush();280.}281.}282.283.//服务器线程284.class ServerThread extends Thread{285.private ServerSocket serverSocket;286.private int max;//人数上限287.288.//服务器线程的构造方法289.public ServerThread(ServerSocket serverSocket,int max){290.this.serverSocket=serverSocket;291.this.max=max;292.}293.294.public void run(){295.while(true){//不停的等待客户端的链接296.try{297.Socket socket=serverSocket.accept();298.if(clients.size()==max){//如果已达人数上限299.BufferedReader r=new BufferedReader( 300.new InputStreamReader(socket.getInputStream()));301.PrintWriter w=new PrintWriter(socket 302..getOutputStream());303.//接收客户端的基本用户信息304.String inf=r.readLine();305.StringTokenizer st=new StringTokenize r(inf,"@");er user=new User(st.nextToken(),st .nextToken());307.//反馈连接成功信息308.w.println("MAX@服务器:对不起,"+user.getName()309.+user.getIp()+",服务器在线人数已达上限,请稍后尝试连接!");310.w.flush();311.//释放资源312.r.close();313.w.close();314.socket.close();315.continue;316.}317.ClientThread client=new ClientThread(socket);318.client.start();//开启对此客户端服务的线程319.clients.add(client);320.listModel.addElement(client.getUser().getName( ));//更新在线列表321.contentArea.append(client.getUser().getName() 322.+client.getUser().getIp()+"上线!\r\n");323.}catch(IOException e){324. e.printStackTrace();325.}326.}327.}328.}329.330.//为一个客户端服务的线程331.class ClientThread extends Thread{332.private Socket socket;333.private BufferedReader reader;334.private PrintWriter writer;335.private User user;336.337.public BufferedReader getReader(){338.return reader;339.}340.341.public PrintWriter getWriter(){342.return writer;343.}344.345.public User getUser(){346.return user;347.}348.349.//客户端线程的构造方法350.public ClientThread(Socket socket){351.try{352.this.socket=socket;353.reader=new BufferedReader(new InputStreamReader( socket354..getInputStream()));355.writer=new PrintWriter(socket.getOutputStream()); 356.//接收客户端的基本用户信息357.String inf=reader.readLine();358.StringTokenizer st=new StringTokenizer(inf,"@"); er=new User(st.nextToken(),st.nextToken()); 360.//反馈连接成功信息361.writer.println(user.getName()+user.getIp()+"与服务器连接成功!");362.writer.flush();363.//反馈当前在线用户信息364.if(clients.size()>0){365.String temp="";366.for(int i=clients.size()-1;i>=0;i--){ 367.temp+=(clients.get(i).getUser().getName()+ "/"+clients368..get(i).getUser().getIp())369.+"@";370.}371.writer.println("USERLIST@"+clients.size()+"@"+temp);372.writer.flush();373.}374.//向所有在线用户发送该用户上线命令375.for(int i=clients.size()-1;i>=0;i--){376.clients.get(i).getWriter().println(377."ADD@"+user.getName()+user.getIp( ));378.clients.get(i).getWriter().flush();379.}380.}catch(IOException e){381. e.printStackTrace();382.}383.}384.385.@SuppressWarnings("deprecation")386.public void run(){//不断接收客户端的消息,进行处理。

相关主题