一个简单的UDP聊天室

以下资料是从别处直接Copy的,为了方便查找使用,放到“毕设手记”里了

一个简单的使用UDP协议实现的联天室,附件中有Eclipse3.4调试的project。

由两个包组成:server 和 client

 

server包里有如下两个类:

 

package server;

import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class ServerFrame extends JFrame{

 private JTextArea allmsg;
 private JTextField currnum,totalnum,copyright,chatmsg;
 private JButton send;
 private JScrollPane js;
 int num1,num2,port;/*  -- num1:当前在线人数  num2:总上线人数  port:服务端口号 --*/
 
 private ServerSocket ss;
 
 ArrayList lists;//存放所有在线用户
 
 public ServerFrame()
 {
  super("聊天室服务器端");
  this.setSize(310,660);
  this.setLocation(200,50);
  
  lists = new ArrayList();
  
  num1 = num2 =0;
  port = 7777;
  
  currnum = new JTextField(" 当前在线人数: "+num1);
  currnum.setEnabled(false);
  
  totalnum = new JTextField(" 上线总人数: "+num2);
  totalnum.setEnabled(false);
  
  copyright = new JTextField("             -----  all copyright @ TOP-king  -----");
  copyright.setEnabled(false);  
  
  allmsg = new JTextArea();
  allmsg.append("                   --------------- 系统消息 --------------\n");
  allmsg.setEditable(false);
  allmsg.setLineWrap(true); //允许自动换行

  js = new JScrollPane(allmsg);//为JTextArea添加滚动条  

  
  chatmsg = new JTextField("在此输入系统信息");
  chatmsg.addActionListener(new ActionListener(){   

   public void actionPerformed(ActionEvent arg0) {
    String str = chatmsg.getText().trim();
    if(!"".equals(str))
      {sendmsg((new Date()).toLocaleString()+" -- 系统消息: "+str);chatmsg.setText("");}
    else
         JOptionPane.showMessageDialog(null, "消息不能为空","错误",JOptionPane.OK_OPTION);
    chatmsg.setText("");/*  -- 发送信息后,将输入栏中的信息清空 --  */
   }
  }); 
  
  send = new JButton("发送");
  send.addActionListener(new ActionListener(){   

   public void actionPerformed(ActionEvent arg0) {
    String str = chatmsg.getText().trim();
    if(!"".equals(str))
      {sendmsg((new Date()).toLocaleString()+" -- 系统消息: "+str);chatmsg.setText("");}
    else
         JOptionPane.showMessageDialog(null, "消息不能为空","错误",JOptionPane.OK_OPTION);
    chatmsg.setText("");/*  -- 发送信息后,将输入栏中的信息清空 --  */
   }
  });
  
  addcomponettocontainer();
  this.addWindowListener(new WindowAdapter(){
   public void windowClosing(WindowEvent we)
   {
    sendmsg("SYSTEM_CLOSED");/*  -- 向客户端发送服务器关闭信息 --  */
    destory();
   }
  });
  start(); /*  -- 启动连接服务 --  */
    
 }
 
 public void addcomponettocontainer()
 {
  Container c = this.getContentPane();
  c.setLayout(null);
  
  currnum.setBounds(20,15,130,20);
  totalnum.setBounds(155,15,125,20);
  js.setBounds(10,50,280,500);
  chatmsg.setBounds(10,560,180,30);
  send.setBounds(220,560,70,30);
  copyright.setBounds(10,600,280,20);
  
  c.add(currnum);
  c.add(totalnum);
  c.add(js);
  c.add(chatmsg);
  c.add(send);
  c.add(copyright);
  
  this.setVisible(true);
  this.setResizable(false);
 }
 
 
 /**  
  *  start()方法监听客户的连接
  *  并且保存客户端的相关信息EG:用户昵称、用户所使用的Socket
  *  用户连接到服务器成功之后,将其保存到用户列表中,并为该用户启动一个线程用于通信 */
 public void start()
 {
  boolean isStarted = false;/*  -- 用于标记服务器是否已经正常启动 --  */
  try {
   this.ss = new ServerSocket(port);
   isStarted = true;
   this.allmsg.append((new Date()).toLocaleString()+"    服务器启动 @ 端口: "+port+"\n");
   while(isStarted)
   {
    Socket client = this.ss.accept(); /*  -- 监听客户端的连接 --  */
    DataInputStream in = new DataInputStream(client.getInputStream());
    String name = in.readUTF();
    user u = new user();
    u.name = name;
    u.socket = client;
    lists.add(u); //将该用户加到列表中去
    num1++;
    num2++;
    currnum.setText(" 当前在线人数: "+num1);
    totalnum.setText(" 上线总人数: "+num2);
    this.allmsg.append((new Date()).toLocaleString()+" : "+u.name+" 登录 \n");
    new Thread(new ClientThread(u)).start();/*  -- 为该用户启动一个通信线程 --  */
   }
   
  } catch (IOException e) {
   System.out.println("服务器已经启动......");
   System.exit(0);
  }
 }

 /**
  * 通信线程主要功能包括:
  * 1.监听客户端输入的信息
  * 2.将接收到的信息转发给其他用户  */
 class ClientThread implements Runnable
 {
  user user = null;
  boolean isConnected = true;
  DataInputStream dis = null;
  DataOutputStream dos = null;
  
  public ClientThread(user u)
  {
      this.user = u; 
      try {
    this.dis = new DataInputStream(this.user.socket.getInputStream());
    this.dos = new DataOutputStream(this.user.socket.getOutputStream());
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
  
  public void run()
  {
   readmsg();
  }
  
  /*  -- 读取客户的聊天信息 --  */
   public void readmsg()
   {
    while(isConnected)
    {
     try {         
      String msg = dis.readUTF();
      if("quit&logout".equals(msg))//当用户关闭客户端窗口时,发送quit字符串 表示用户已经退出
      {
       num1--;       
       try{
        this.dis.close();
        this.dos.close();
        this.user.socket.close();
        this.isConnected = false;
       }catch(IOException ioe)
       {
        ioe.printStackTrace();
       }finally{
        this.isConnected = false;
        if(dis!=null) this.dis.close();
        if(dos!=null) this.dos.close();
        if(this.user.socket!=null) this.user.socket.close();
       }
       lists.remove(this.user);//从列表中删除该用户
       currnum.setText(" 当前在线人数: "+num1);
       allmsg.append((new Date()).toLocaleString()+"  : "+this.user.name+"  退出\n");
      }
      else
      sendmsg(msg);
     } catch (IOException e) {
      e.printStackTrace();
     }
   }
   }    
     
 }
   
 /*  -- 将信息进行转发 --  */
 public void sendmsg(String msg)
    {
     user us = new user();
     DataOutputStream os = null;
     if(lists.size()>0)
     {
      for(int i=0;i<lists.size();i++)
         {
             us = (user)lists.get(i);
             try {   
              os = new DataOutputStream(us.socket.getOutputStream());
        os.writeUTF(msg);
       } catch (IOException e) {
        e.printStackTrace();
       }
         }
     } 
     else
      JOptionPane.showMessageDialog(null, "当前无用户在线。发送消息失败","失败",JOptionPane.OK_OPTION);
    } 
 
    public void destory()
    {
     try {
   this.ss.close();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  this.dispose();
    }
    
 public static void main(String[] args)
 {
  new ServerFrame();
 }

}

 

 

 

package server;

import java.net.*;

public class user {

  String name;
  Socket socket;
}

 

 

 

client包里有如下两个类:

 

1.

 

package client;

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;

public class LoginFrame extends JFrame{
 private JTextField name;
 private JTextField ip;
 private JButton ok,cancle;
  
 public Socket socket;
 
 public LoginFrame()
 {
  super("登录框");
  this.setSize(400,80);
  this.setLocation(100,100);  
   
  name = new JTextField("昵称");   
  ip = new JTextField("127.0.0.1");
  ok = new JButton("登录");
  cancle = new JButton("取消");
  ok.addActionListener(new listenEvent());
  cancle.addActionListener(new listenEvent());
  
  addcomponettocontainer();
  this.setDefaultCloseOperation(EXIT_ON_CLOSE);
  
 }

 public void addcomponettocontainer()
 {
  Container c = this.getContentPane();
  c.setLayout(null);
  
  name.setBounds(10,10,100,30);
  ip.setBounds(120,10,100,30);
  ok.setBounds(230,10,70,30);
  cancle.setBounds(310,10,70,30);
  
  c.add(name);
  c.add(ip);
  c.add(ok);
  c.add(cancle);
  
  this.setVisible(true);
  this.setResizable(false);
 }
 
 public class listenEvent implements ActionListener
 {

  public void actionPerformed(ActionEvent event) {
   // TODO Auto-generated method stub
   if(event.getSource()==ok)
   {
    String n = name.getText().trim();
    String i = ip.getText().trim();
    if("".equals(n)||"".equals(i))
    {
     JOptionPane.showMessageDialog(null,"昵称、IP不能够为空!","错误",JOptionPane.OK_OPTION);
    }
    else{login(n,i);}
   }
   if(event.getSource()==cancle)
   {
    name.setText("");
    ip.setText("");
   }
  }
  
 }
 
 public void login(String name,String ip)
 {
  
   try {
    socket = new Socket(ip,7777);
    DataOutputStream out = new DataOutputStream(socket.getOutputStream());
    out.writeUTF(name);
    out.flush();//强制输出缓存中的内容
    //out.close();
    new ClientFrame(name,socket);
    destroywindow();
   } catch (UnknownHostException e) {
    JOptionPane.showMessageDialog(null,"找不到主机地址(IP错误/网络故障)!","错误",JOptionPane.OK_OPTION);
    
   } catch (IOException e) {
    
   }         
 }
 
 public void destroywindow()
 {  
  this.dispose();
 }
 
 public static void main(String[] args)
 {
  new LoginFrame();
 }
}

 

 

package client;

import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Date;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class ClientFrame extends JFrame{
 private JTextArea allmsg;
 private JTextField welcome,copyright,chatmsg;
 private JButton send;
 private JScrollPane js;
    private boolean isConnected = true;
 
 public DataOutputStream out;
 public DataInputStream in;
 
 public Socket s = null; 
 
 String nic;  /*  -- 保存用户昵称 --*/
 
 
 /**
  * 初始化客户端资源
  * 1.获取从LoginFrame传递过来的参数
  * 2.初始化界面元素
  * 3.初始化通信所需要的资源 EG:输入/输出流(DataInputStream/DataOutputStream)
  * */ 
 public ClientFrame(String name,Socket socket)
 {  
  this.setSize(310,660);
  this.setLocation(290,50);  
        this.setTitle("聊天室客户端<"+name+">");/*  -- 指定窗口的标题 --*/
        
  this.s = socket;/*  -- 接收从LoginFrame中传递过来的Socket --*/  
  
  this.nic = name+" 说: ";
  
  
  welcome = new JTextField(" < "+name+" >欢迎您来到聊天室 ",100);
  welcome.setBackground(Color.blue);  
  welcome.setEnabled(false);
  
  copyright = new JTextField("             -----  all copyright @ TOP-king  -----");
  copyright.setEnabled(false);
  
  allmsg = new JTextArea();
  allmsg.setEditable(false);
  allmsg.append("                  系统消息: 欢迎登录在线聊天室 \n");
  
  js = new JScrollPane(allmsg);//为JTextArea添加滚动条  
  
  chatmsg = new JTextField("在此输入聊天信息");
  chatmsg.addActionListener(new listen());
  
  send = new JButton("发送");
  send.addActionListener(new listen());/*  -- 添加事件监听器 --*/
  
  try {    
   out = new DataOutputStream(s.getOutputStream());   
   in = new DataInputStream(s.getInputStream());   
  } catch (IOException e) {JOptionPane.showMessageDialog(null, "系统异常","错误",JOptionPane.OK_CANCEL_OPTION);}
  
  addcomponettocontainer();

  /*  -- 当用户关闭窗口时进行相关的处理 eg:Socket Data(Input/Output)Stream 的关闭--*/
  this.addWindowListener(new WindowAdapter(){
   public void windowClosing(WindowEvent we)
   {
    sendmsg("quit&logout");/*  -- 向服务器端发送关闭信息 --*/
    isConnected = false;
    destory();/*  -- 销毁窗口资源 --*/
   }
  });
  
  new Thread(new linread()).start();/*  -- 启动读取信息线程 --*/
  
 }
 
 public void addcomponettocontainer()
 {
  Container c = this.getContentPane();
  c.setLayout(null);
  
  welcome.setBounds(75,10,150,20);  
  js.setBounds(10,50,280,500);
  chatmsg.setBounds(10,560,180,30);
  send.setBounds(220,560,70,30);
  copyright.setBounds(10,600,280,20);
  
  c.add(welcome);
  c.add(js);
  c.add(chatmsg);
  c.add(send);
  c.add(copyright); 
    
  this.setVisible(true);
  this.setResizable(false);
 }
 
 class listen implements ActionListener
 {

  public void actionPerformed(ActionEvent e) {
   // TODO Auto-generated method stub
   if(e.getSource()==send||e.getSource()==chatmsg)
   {
      String msg = chatmsg.getText().trim();
      if("".equals(msg))
      {
       JOptionPane.showMessageDialog(null,"发送信息不能为空!","错误",JOptionPane.OK_OPTION);
      }
      else
      {sendmsg((new Date()).toLocaleString()+"\n"+nic+msg+"\n");chatmsg.setText("");}
   }
  } 
 }
 
 /*  -- 向服务器端发送信息 --*/
  public void sendmsg(String m)
  {
   if(isConnected)//如果socket的输出流没关闭
   {
    try {
     out.writeUTF(m);
    } catch (IOException e) {
     JOptionPane.showMessageDialog(null,"发送信息失败!(系统异常)","错误",JOptionPane.OK_OPTION);
    }
   }
   else
   {
    JOptionPane.showMessageDialog(null,"发送信息失败!(服务器关闭/网络故障)","错误",JOptionPane.OK_OPTION);
   }
  }

  /*  -- 读取信息线程 --*/
 class linread implements Runnable
 {  
  public void run()
  {
   read();
  }
  
  public void read()
  {
    while(isConnected)
    {
     try {
      String msg = in.readUTF();
      if("SYSTEM_CLOSED".equals(msg))
      {
       JOptionPane.showMessageDialog(null,"读取消息失败(服务器关闭/网络故障)!","错误",JOptionPane.OK_OPTION);
       isConnected = false;
      }
      else
        allmsg.append(msg+"\n");      
      } catch (IOException e) {     
      }                  
    }//end while 
    JOptionPane.showMessageDialog(null,"读取消息失败(服务器关闭/网络故障)!","错误",JOptionPane.OK_OPTION);
   }//end read()
 }
 
  public void destory()
  {
   try {
    this.out.close();
    this.in.close();
    this.s.close();
   } catch (IOException e) {   
   }
   this.dispose();
  }
}

 

 

 

二、运行情况

 



 



 



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值