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