【Java线程】简单实现带界面的一对一聊天

  • Post author:
  • Post category:java



实现原理:

1、构建好窗体,在窗体中创建好相应的布局和控件;

2、为相应的控件(按钮:监听、连接、发送)添加事件;

3、使用到两个线程:

a、监听线程:获取服务器端输入的端口号,构建socket,监听相应端口,等待客户端来连接;
b、坚守网络阵地的线程:从网路中获取信息,并将其写出到屏幕;


源码如下:


JFrameTcp.java

/**
 * @author lmb
 * 实现带界面的一对一聊天
 */
public class JFrameTcp extends JFrame implements ActionListener{

    private JTextField ipText;
    private JTextField portText;
    private JButton listen;
    private JButton connect;
    private TextArea msg;
    private JButton send;
    private JTextField c;
    private Socket skt;


    public JFrameTcp(){//构造方法,初始化窗体中的组件
        this.setBounds(100,100,500,400);//设置窗体大小
        Container cc=this.getContentPane();//构建容器
        cc.setLayout(new BorderLayout());//设置容器cc的布局
        //上
        Panel p1=new Panel();
            JLable ip=new JLable("IP:");//构建IP标签
            p1.add(ip);//将其加入到p1容器中
            ipText=new JTextField(13);//构建ip后的输入框
            p1.add(ipText);//将其加入到p1容器中
            JLable port=new JLable("Port:");//构建port标签
            p1.add(port);//将其加入到p1容器中
            portText=new JTextField(6);//构建port后的输入框
            p1.add(portText);//将其加入到p1容器中
            listen=new JButton("监听");//构建监听按钮
            p1.add(listen);//将其加入到p1容器中
            connect=new JButton("连接");//构建连接按钮
            p1.add(connect);//将其加入到p1容器中
        cc.add(p1,BorderLayout.NORTH);//将容器p1加入到容器cc的上边
        //中
        Panel p2=new Panel();
            p2.setLayout(new BorderLayout());//设置p2的布局方式
            msg=new TextArea();//构建消息显示框
            p2.add(msg,BorderLayout.CENTER);//将消息显示框添加到p2的中间
        cc.add(p2,BorderLayout.CENTER);//将容器p1加入到容器cc的中间
        //下
        Panel p3=new Panel();
            p3.setLayout(new BorderLayout());//为容器p3设置一个布局方式
            sendText=new JTextField(20);//构建send前的输入框
            p3.add(sendText,BorderLayout.CENTER);//将其加入到p3容器的中间
            send=new JButton("发送");//构建发送按钮
            p3.add(send,BorderLayout.EAST);//将其加入到p3容器的右边
        cc.add(p3,BorderLayout.SOUTH);//将容器p1加入到容器cc的下边

        //给按钮添加事件
        listen.addActionListener(this);
        connect.addActionListener(this);
        send.addActionListener(this);

    }

    //事件方法
    public void actionPerformed(ActionEvent e){
        if (e.getSource() == listen) {
            doListen();//服务器端调用该方法,监听端口,等待客户端来连接
        }
        if (e.getSource() == connect) {
            doConnect();//客户端调用该方法,向服务器端发起连接
        } 
        if (e.getSource() == send) {
            doSend();//发送消息
        } 
    } 

    //发送消息
    private void doSend() {
        String s=sendText.getText();//获取发送框中的信息
        try {
            //构建输出流,将从发送框获取的信息写入到网络
            PrintWriter pw=new PrintWriter(skt.getOutputStream());
            pw.println(s);
            pw.flush();
            sendText.setText("");//每次点击发送之后将文本框置空
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //连接
    private void doConnect() {
        try {
            skt=new Socket(ipText.getText(), 
                    Integer.parseInt(portText.getText()));
            new Net().start();//启动一个线程来坚守网络
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //监听
    private void doListen() {
        //为什么要使用线程:监听的时候会发生阻塞,使用线程来避免阻塞
        new ListenThread().start();//在线程中实施监听
        new Net().start();//启动一个线程来坚守网络
    }

    /**
     * 监听线程(内部类)
     * 使用内部类的原因:在该线程中要使用portText、appendMsg两个变量,我们可以在开启线程的时候使用构造方法
     *          将这两个变量传进来,但是如果我们在线程中要用到的变量比较多,这时候再用构造方法来传变量就相当麻烦了,
     *          于是,我们可以使用内部类来达到直接使用外部类成员变量的目的。
     *
     */
    class ListenThread extends Thread{
        public void run(){
            String s=portText.getText();//获取portText中输入的端口号
            ServerSocket sskt=null;
            try {
                sskt=new ServerSocket(Integer.parseInt(s));
                //当开始监听时给出提示信息
                appendMsg.append("监听中……\n");
                skt=sskt.accept();//等待其他人来连接
                appendMsg.append(skt.getInetAddress().getHostAddress() + "与我建立连接\n");

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //用来坚守网络阵营,然后将从网络中获取的信息写出到屏幕
    class Net extends Thread{
        public void run(){
            try {
                BufferedReader br=new BufferedReader(
                        new InputStreamReader(skt.getInputStream()));
                for (;;) {
                    appendMsg.append(skt.getInetAddress().getHostAddress() + 
                            ":" + br.readLine() + "\n");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    public static void main(String[] args) {
        new JFrameTcp().setVisible(true);//设置窗体可见
    }

}


运行效果:

这里写图片描述

该例只是简单实现了一下一对一聊天的主要功能,其中还有好多问题没有解决,不如:在没有输入端口号和IP地址的情况下直接发送消息,也是可以发送的,等等,边学边改进,努力做到更好,后续会有更好的实现!



版权声明:本文为lmb55原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。