java自己写的简单聊天工具SimpleQQ感悟

Demo如下:

 

 

客户端:

/*
 * 一个简单的QQ
 * 2013-8-1
 * @李志杰
 */
package SimpleQQ_Client;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;

public class DemoQQ_Client
{
    public static void main(String[] args)
    {
        // TODO Auto-generated method stub
        DemoQQ_Client demoQQ_Server_1 = new DemoQQ_Client();
    }
    public DemoQQ_Client()
    {
        
        //初始化界面,开始界面的多线程
        MyPanel mp;        
        mp = new MyPanel();
        
        Thread t1 = new Thread(mp);
        t1.start();
        
        //服务器getter
        MyClient mServer = new MyClient();
        Thread t2 = new Thread(mServer);
        t2.start();
        
        //服务器sender
        MyClient_writer myClient_writer = new MyClient_writer();
        Thread t3 = new Thread(myClient_writer);
        t3.start();
        
        /*
        //测试线程
        Mytest mytest = new Mytest();
        Thread t4 = new Thread(mytest);
        t4.start();
        */
    }
}

//共享参数类
class MyBaseClient
{
    //定义参数,务必让发送信息和接收信息的参数共享
    static Socket s;
    static String send_ino,get_ino;

}

class MyClient_writer extends MyBaseClient implements Runnable //QQ写者
{

    @Override
    public void run()
    {
        // TODO Auto-generated method stub
        while(true)
        {
            try
            {
                Thread.sleep(500);
            }
            catch (InterruptedException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            sendIno();
            send_ino = null;
        }
    }
    //发送信息
        public void sendIno()
        {
            if(send_ino == null)
            {
                return;
            }
            try
            {
                //发送数据
                PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
                //获取发送内容
                pw.println(send_ino);
                send_ino = "Client :" + send_ino +"\n";
                
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
}

class MyClient extends MyBaseClient implements Runnable
{        
    public MyClient()
    {
        //下面是主要功能
        try
        {
            s = new Socket("127.0.0.1", 9999);
            get_ino = "欢迎使用星尘QQ简易版\n";
        }
        catch (IOException e)
        {
                // TODO Auto-generated catch block
                e.printStackTrace();
        }        
    }

    //传递返回信息
    public void getIno()
    {
        try
        {
            //读数据
            InputStreamReader inr = new InputStreamReader(s.getInputStream());
            BufferedReader bf = new BufferedReader(inr);
            get_ino = "Server :"+bf.readLine()+"\n";
        }
        catch (IOException e)
        {
            System.out.println("Error!");
            return;
        }
    }
    
    @Override
    public void run()
    {
        // TODO Auto-generated method stub
        while(true)
        {
            try
            {
                Thread.sleep(500);
            }
            catch (InterruptedException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            getIno();

        }
    }
}


//专门的界面类,以后要用这种方式去画界面,不要用视频教程里面的
class MyPanel extends JFrame implements Runnable,ActionListener
{
    
    //定义参数
    String sender,getter;
    MyBaseClient mbc = new MyBaseClient();
    //定义组件
    JPanel jp;
    JTextArea jta;
    JButton jb;
    JTextField jt;
    JScrollPane jsp;
    
    public MyPanel()
    {
        

        //创建组件
        jp = new JPanel();
        jta = new JTextArea();
        jb = new JButton("发送");
        jt = new JTextField();
        jsp = new JScrollPane(jta);
        
        jt.setCaretColor(Color.GREEN);//jt绿色光标
        jt.setForeground(Color.GREEN);//jt绿色字体
        
        //信息区只能读
        jta.setEditable(false);
        //添加监听
        jb.setActionCommand("send");
        //注册监听
        jb.addActionListener(this);
        
        //添加组件
        jp.setLayout(new GridLayout(2,1));
        
        jp.add(jt);
        jp.add(jb);
        
        this.setLayout(new GridLayout(2,1));
        this.add(jsp);
        this.add(jp);
        
        this.setSize(400,400);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("QQ_Client");
        
    
    }
    public void paint(Graphics g)
    {
        super.paint(g);
    }
    @Override
public void run()
{
    while(true)
    {
        try
        {
            Thread.sleep(500);
           
        }
        catch (InterruptedException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        sender = this.jt.getText();
        getter = mbc.get_ino;
        //更新面板
        if(getter == null) //信息为空,跳过更新
        {
            continue;
        }
        if(mbc.get_ino != null)
        {
            String s_board = this.jta.getText() + getter;        //通过面板来获取记录
            this.jta.setText(s_board);
            mbc.get_ino = null;
        }
        this.repaint();    
    }
}
    @Override
  public void actionPerformed(ActionEvent e)
  {
        if(e.getActionCommand() == "send")
        {
            //发送信息
            mbc.send_ino = sender;        //更新消息缓存
            String s_board = this.jta.getText() + "Client :" +sender +"\n";        //通过面板来获取记录
            this.jta.setText(s_board);
            jt.setText(null);//清空内容
            this.repaint();    
        }
  }
}


//测试类
class Mytest extends MyBaseClient implements Runnable
{

    int times = 0;
  public void run()
  {
        // TODO Auto-generated method stub
        try
      {
            while(true)
            {
                times++;
                Thread.sleep(100);
                System.out.println("Time :"+ times + " " + get_ino);
            }
      }
      catch (Exception e)
      {
            // TODO: handle exception
      }
  }
    
}

 

服务器端的:

/*
 * 一个简单的QQ
 * 2013-8-1
 * @李志杰
 */
package SimpleQQ_Server;
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

import java.io.*;
import java.net.*;

public class DemoQQ_Server
{
    public static void main(String[] args)
    {
        // TODO Auto-generated method stub
        DemoQQ_Server demoQQ_Server = new DemoQQ_Server();
    }
    public DemoQQ_Server()
    {
        
        //初始化界面,开始界面的多线程
        MyPanel mp;        
        mp = new MyPanel();
        
        Thread t1 = new Thread(mp);
        t1.start();
        
        //服务器getter
        MyServer mServer = new MyServer();
        Thread t2 = new Thread(mServer);
        t2.start();
        
        //服务器sender
        MyServer_writer myClient_writer = new MyServer_writer();
        Thread t3 = new Thread(myClient_writer);
        t3.start();
        
    }
}

//共享参数类
class MyBaseServer
{
    //定义参数,务必让发送信息和接收信息的参数共享
    static Socket s;
    static ServerSocket ss;
    static String send_ino,get_ino;
}

class MyServer_writer extends MyBaseServer implements Runnable //QQ写者
{

    @Override
    public void run()
    {
        // TODO Auto-generated method stub
        while(true)
        {
            try
            {
                Thread.sleep(500);
            }
            catch (InterruptedException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            sendIno();
            send_ino = null;
            //get_ino = null;
        }
    }
    //发送信息
        public void sendIno()
        {
            if(send_ino == null)
            {
                return;
            }
            try
            {
                //发送数据
                PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
                //获取发送内容
                pw.println(send_ino);
                send_ino = "Client :" + send_ino +"\n";
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
}

class MyServer extends MyBaseServer implements Runnable
{        
    public MyServer()
    {
        //下面是主要功能
        try
        {
            get_ino = "欢迎使用星尘QQ简易版\n";
            ss = new ServerSocket(9999);
            s = ss.accept();
        }
        catch (IOException e)
        {
                // TODO Auto-generated catch block
                e.printStackTrace();
        }        
    }

    //传递返回信息
    public void getIno()
    {
        //要拥有一个判断去跳出这个读取,否则一旦进入try块,如果没有信息进来,读者会一直占用cpu而不会进入到写者,除非写者也开多线程
        /*
        if(get_ino == null)
        {
            return;
        }
        */
        try
        {
            //读数据
            InputStreamReader inr = new InputStreamReader(s.getInputStream());
            BufferedReader bf = new BufferedReader(inr);
            get_ino = "Server :"+bf.readLine()+"\n";
        }
        catch (IOException e)
        {
            return;
        }
    }
    
    @Override
    public void run()
    {
        // TODO Auto-generated method stub
        while(true)
        {
            try
            {
                Thread.sleep(500);
            }
            catch (InterruptedException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            getIno();
            //sendIno();
           // send_ino = null;
            //get_ino = null;
        }
    }
}


//专门的界面类,以后要用这种方式去画界面,不要用视频教程里面的
class MyPanel extends JFrame implements Runnable,ActionListener
{
    
    //定义参数
    String sender,getter;
    MyBaseServer mbs = new MyBaseServer();
    //定义组件
    JPanel jp;
    JTextArea jta;
    JButton jb;
    JTextField jt;
    JScrollPane jsp;
    
    public MyPanel()
    {
        

        //创建组件
        jp = new JPanel();
        jta = new JTextArea();
        jb = new JButton("发送");
        jt = new JTextField();
        jsp = new JScrollPane(jta);
        
        jt.setCaretColor(Color.RED);//jt红色光标
        jt.setForeground(Color.RED);//jt红色字体
        
        //信息区只能读
        jta.setEditable(false);
        //添加监听
        jb.setActionCommand("send");
        
        
        //注册监听
        jb.addActionListener(this);
        
        //添加组件
        jp.setLayout(new GridLayout(2,1));
        
        jp.add(jt);
        jp.add(jb);
        
        this.setLayout(new GridLayout(2,1));
        this.add(jsp);
        this.add(jp);
        
        this.setSize(400,400);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("QQ_Server");
        
    
    }
    public void paint(Graphics g)
    {
        super.paint(g);
    }
    @Override
public void run()
{
    while(true)
    {
        try
        {
            Thread.sleep(500);
           
        }
        catch (InterruptedException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        sender = this.jt.getText();
        getter = mbs.get_ino;
        //更新面板
        //更新面板
        if(getter == null) //信息为空,跳过更新
        {
            continue;
        }
        if(mbs.get_ino != null)
        {
            String s_board = this.jta.getText() + getter;        //通过面板来获取记录
            this.jta.setText(s_board);
            mbs.get_ino = null;
        }
        this.repaint();    
    }
}
    @Override
  public void actionPerformed(ActionEvent e)
  {
        if(e.getActionCommand() == "send")
        {
            //发送信息
            mbs.send_ino = sender;        //更新消息缓存
            String s_board = this.jta.getText() + "Client :" +sender +"\n";        //通过面板来获取记录
            this.jta.setText(s_board);
            jt.setText(null);//清空内容
            this.repaint();    
        }
  }
}

 

总结:

  先说一下这个简单项目的设计思路:

  1、本着模块独立化的思路,将整个项目的两个模块(界面+通讯)独立成三个类,其中界面类为MyPanel,通讯(这里以客户端为例)为MyClient(接收消息)和MyClient_writer(发送消息)。

  2、除了以上三个类外,还设计了一个共享信息的类,即MyBaseClient,通讯的两个类直接继承这个类,界面类通过将这个类实例化来共享这个类的变量信息;

  3、此项目还有一个特色的地方是,使用了三个线程,一个是界面线程用以定时绘图和监听按钮,另一个是接收消息的类,用以定时接收消息。除了这两个外,还有一个用以发送消息。之所以要这样设计,首先是要让界面与后台逻辑分离,即界面与通讯分离,其次是要让后台中的读写分离,实现同步和实时。

  这是我今天的技术收获,记此。

 

posted @ 2013-08-01 23:27  月之星狼  阅读(5819)  评论(1编辑  收藏  举报