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