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、此項目還有一個特色的地方是,使用了三個線程,一個是界面線程用以定時繪圖和監聽按鈕,另一個是接收消息的類,用以定時接收消息。除了這兩個外,還有一個用以發送消息。之所以要這樣設計,首先是要讓界面與后台邏輯分離,即界面與通訊分離,其次是要讓后台中的讀寫分離,實現同步和實時。

  這是我今天的技術收獲,記此。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM