Java——基于GUI的网络通信程序设计【强迫症版本】

一、实验目的

1.掌握Java中GUI程序的编写,包括事件监听机制。

2.掌握Java的网络通信编程,ServerSocket,Socket类的使用。

3.掌握Java中多线程的编程,Thread类,Runnable接口的使用。

4.掌握用面向对象的方法分析和解决复杂问题。

二、实验原理

1.使用面向对象的设计方法设计程序

2.通过继承JFrame类实现图形化界面

3.通过事件监听器实现按钮点击监听与触发事件

4.利用ServerSocket和Socket类实现网络通信

5.利用多线程技术实现同时读入数据与发送数据

三、使用硬件、软件环境

硬件环境:PC计算机一台,配置CPU为Intel(R)Core(TM)i7-8565U CPU @1.80Ghz内存为8.0GB,硬盘256G+1T(机械硬盘),安装系统为Windows10操作系统。
软件环境:IDEA,JDK12.0

四、实验过程

在这里插入图片描述
①服务器:

//Author:Sherlock Novitch in Hfut
// -*- codeing=utf-8 -*-
// @time:2020/10/19 15:14
// @File:ServerFrame.java
// @Software:IDEA
// @blog:https://blog.csdn.net/RealCoder

package experiment2;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.*;

public class ServerFrame extends JFrame {
    private JTextField text1,text2; //text1为端口号文本栏,text2为消息输入栏
    private JTextArea text;         //消息显示区
    private JButton button1,button2; //button1对应start,button2对应say
    private ServerSocket server;    //服务器套接字
    private Socket sc;              //与客户端建立联系的套接字
    private DataInputStream in;     //客户端到服务器的输入流
    private DataOutputStream out;   //服务器到客户端的输出流
    private ReadThread readThread;  //负责读入信息的线程
    private myactionlistenr ac;   //监听两个按钮的监听器
    private ServerFrame(){          //构造方法
        setLayout(new FlowLayout()); //窗体容器整体布局设置为FlowLayout
        GUIinit();                     //调用组件初始化方法
        eventinit();               //调用事件监听器初始化方法
        setVisible(true);         //设置可视
        setResizable(false);      //设置不可更改大小
        setDefaultCloseOperation(EXIT_ON_CLOSE); //在关闭窗体时,程序终止

    }
    private void GUIinit(){
        setTitle("服务器");    //设置标题
        setBounds(100,250,500,300);  //位置与大小
        Box boxH1=Box.createHorizontalBox(); //创建水平盒式容器,后续依次从左到右添加"Port:",text1,button1;
        Box boxH2=Box.createHorizontalBox(); //创建水平盒式容器,后续依次从左到右添加"Say: ",text2,button2;
        Box boxV=Box.createVerticalBox();  //创建垂直盒式容器,后续依次从垂直方向从上向下添加"服务器设置:",boxH1,boxH2
        //1°开始添加“服务器设置:”标签至boxV
        Box temp=Box.createHorizontalBox();
        temp.add(new JLabel("服务器设置:"));
        temp.add(Box.createHorizontalStrut(400)); //添加水平支撑(类似Qt中的弹簧)
        boxV.add(temp);
        boxV.add(Box.createVerticalStrut(5));//添加垂直支撑(类似Qt中的弹簧)
        //2°开始填装boxH1,之后加入到boxV中
        boxH1.add(new JLabel("Port:"));
        boxH1.add(Box.createHorizontalStrut(5));
        text1=new JTextField();
        boxH1.add(text1);
        boxH1.add(Box.createHorizontalStrut(10));
        button1=new JButton("Start");
        boxH1.add(button1);
        boxV.add(boxH1);
        boxV.add(Box.createVerticalStrut(10));
        //3°开始添加文本显示区至boxV
        text=new JTextArea(9,30);
        JScrollPane jScrollPane=new JScrollPane(text);  //将text放置到滚动窗格(一种容器)中
        text.setEditable(false);
        jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
                                                       //当text内文本高度超过text高度时,text出现竖直滚动条
        boxV.add(jScrollPane);
        boxV.add(Box.createVerticalStrut(10));
        //4°开始填装boxH2,之后将boxH2加入到boxV中
        boxH2.add(new JLabel("Say:"));
        boxH2.add(Box.createHorizontalStrut(5));
        text2=new JTextField();
        boxH2.add(text2);
        boxH2.add(Box.createHorizontalStrut(5));
        button2=new JButton("Say");
        boxH2.add(button2);
        boxV.add(boxH2);
        add(boxV);
    }
    private void eventinit(){
        ac=new myactionlistenr();   //初始化监听器
        button1.addActionListener(ac);  //监听器注册
        button2.addActionListener(ac);  //监听器注册
    }
    private void startserver(){  //”开启服务“方法,当点击Start按钮时,监听器检测到,调用此方法
          try {
              server = new ServerSocket(Integer.parseInt(text1.getText())); //用text1文本框内容对应的数字初始化服务器套接字
              text.append("Server starting…\n");                     //服务器端打印"Server starting…"
              text.paintImmediately(text.getBounds()); //本条语句使得Server starting立即显示出来
                                                      // 原因在于append方法只是将参数加至缓冲区
                                                     // 而本线程会被下一行accept方法阻塞
                                                     //调用paintImmediately方法直接将缓冲区内容显示出来
              sc = server.accept();         // 等待客户端连接,初始化与客服端相连接的套接字对象sc
              text.append("Client connected…\n"); //服务器端打印”Client connected…“
              in = new DataInputStream(sc.getInputStream()); //将in初始化为sc的输入流
              out = new DataOutputStream(sc.getOutputStream()); //将out初始化为sc的输出流
              readThread = new ReadThread();               //创建读取数据的线程
              readThread.start();                          //读取数据的线程开始运行
          } catch (IllegalArgumentException e) {  //若端口参数不符合,抛出IllegalArgumentException,用消息对话框提示用户
              JOptionPane.showMessageDialog(this,"端口值范围必须为0~65535","警告",JOptionPane.WARNING_MESSAGE);
          }catch (IOException e){
              JOptionPane.showMessageDialog(this,"未知原因连接错误","警告",JOptionPane.WARNING_MESSAGE);
          }catch (Exception e){
              System.out.println(e.toString());
          }

    }
    private void sentmessage(){  //当say按钮被点击,监听器检测到,调用该方法
        if(readThread==null){    //先判断是否已连接,只需判断readThread是否被创建,未创建则发出提示信息,终止方法
            JOptionPane.showMessageDialog(this,"未连接无法发送信息","警告",JOptionPane.WARNING_MESSAGE);
            return;
        }
        try{
            out.writeUTF("Server: "+text2.getText()+"\n");  //向客户端发送信息
            text.append("Server: "+text2.getText()+"\n");       //同时更新服务器端文本区内容
            text2.setText("");                                 //清空text2
        }catch (IOException e){//异常处理
            JOptionPane.showMessageDialog(this,"未知原因无法发送信息","警告",JOptionPane.WARNING_MESSAGE);
            System.out.println(e.toString());
        }
    }
    class myactionlistenr implements ActionListener { //监视按钮的监听器
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == button1) startserver();   //如果点击的按钮为start,调用startserver方法
            if (e.getSource() == button2) sentmessage();   //如果点击的按钮为say,则调用sentmessage方法
        }
    }
    class ReadThread extends Thread{
        public void run(){
            while(true) {
                try {
                    text.append(in.readUTF());    //将输入流读取的数据添加至文本显示区
                } catch (IOException e) {
                    System.out.println(e.toString());
                }
            }
        }
    }
    public static void main(String[] args) {
        ServerFrame sf=new ServerFrame();
    }
}

②客户端:

//Author:Sherlock Novitch in Hfut
// -*- codeing=utf-8 -*-
// @time:2020/10/19 15:14
// @File:ClientFrame.java
// @Software:IDEA
// @blog:https://blog.csdn.net/RealCoder

package experiment2;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.*;

public class ClientFrame extends JFrame {
    private JTextField text1,text2,text3; //text1为ip地址输入栏,text2为端口地址输入栏,text3为消息输入栏
    private JTextArea text;           //文本显示区
    private JButton button1,button2;  //button1为connect按钮,button2为say按钮
    private Socket client;           //客户端套接字
    private DataInputStream in;     //从服务器到客户端的输入流
    private DataOutputStream out;  //从客户端到服务器的输出流
    private ReadThread readThread; //读取服务器消息的线程
    private actionlistener ac;  //监听按钮button1和button2的监听器
    private ClientFrame() { //构造方法
        setLayout(new FlowLayout()); //窗体整体布局为FlowLayout
        GUIinit();                //调用组件初始化方法
        Eventinit();              //调用事件初始化方法
        setVisible(true);          //设置可见
        setResizable(false);     //设置不可更改大小
        setDefaultCloseOperation(EXIT_ON_CLOSE);  //设置当关闭窗口时,程序终止
    }
    private void GUIinit(){  //组件初始化方法
        setTitle("客户端");  //设置标题
        setBounds(600,250,500,300);  //位置大小
        Box boxH1=Box.createHorizontalBox(); //创建水平盒式容器,后续装入"Server IP:",text1,"Server Port",button1;
        Box boxH2=Box.createHorizontalBox(); //创建水平盒式容器,后续装入"Say:",text3,button2;
        Box boxV=Box.createVerticalBox();  //创建垂直盒式容器,后续装入“客户端设置:",boxH1,text,boxH2;
        //1°boxV装入“客户端设置”标签
        Box temp=Box.createHorizontalBox();
        temp.add(new JLabel("客户端设置:"));
        temp.add(Box.createHorizontalStrut(400));
        boxV.add(temp);
        boxV.add(Box.createVerticalStrut(5));
        //2°将Server IP:",text1,"Server Port",button1从左到右加入到boxH1中,再讲boxH1加入到boxV中
        boxH1.add(new JLabel("Server IP:"));
        boxH1.add(Box.createHorizontalStrut(5));
        text1=new JTextField();
        boxH1.add(text1);
        boxH1.add(Box.createHorizontalStrut(10));
        boxH1.add(new JLabel("Server Port:"));
        boxH1.add(Box.createHorizontalStrut(5));
        text2=new JTextField();
        boxH1.add(text2);
        boxH1.add(Box.createHorizontalStrut(5));
        button1=new JButton("Connect");
        boxH1.add(button1);
        boxV.add(boxH1);
        boxV.add(Box.createVerticalStrut(10));
        //3°将text文本显示区加入到滚动窗格并设置超高度出现竖直滚动条,再将滚动窗口加入到boxV中
        text=new JTextArea(9,30);
        JScrollPane jScrollPane=new JScrollPane(text);
        text.setEditable(false);
        jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        boxV.add(jScrollPane);
        boxV.add(Box.createVerticalStrut(10));
        //4°依次将从左到右“客户端设置:",boxH1,text,boxH2加入到boxH2中,再将boxH3加入到boxV中
        boxH2.add(new JLabel("Say:"));
        boxH2.add(Box.createHorizontalStrut(5));
        text3=new JTextField();
        boxH2.add(text3);
        boxH2.add(Box.createHorizontalStrut(5));
        button2=new JButton("Say");
        boxH2.add(button2);
        boxV.add(boxH2);
        add(boxV);
    }
    private void Eventinit(){
        ac=new actionlistener();//初始化监听器
        button1.addActionListener(ac); //监听器注册
        button2.addActionListener(ac);  //监听器注册
    }
    private void startserver(){  //点击connect按钮后调用的启动客户端服务的方法
        try{
            client=new Socket();   //初始化客户端套接字
            InetAddress address=InetAddress.getByName(text1.getText()); //用text1文本栏中的ip地址创建InetAddress
            InetSocketAddress socketAddress=new InetSocketAddress(address,Integer.parseInt(text2.getText())); //所连接服务器的地址
            client.connect(socketAddress); //连接到服务器
            text.append("Connect to server…\n"); //文本显示区添加“Connect to server…”
            in=new DataInputStream(client.getInputStream());  //初始化输入流
            out=new DataOutputStream(client.getOutputStream()); //初始化输出流
            readThread=new ReadThread();   //创建读取数据的线程
            readThread.start();           //线程开始运行
        }catch (UnknownHostException e){ //IP地址有误,发出提示
           JOptionPane.showMessageDialog(this,"输入IP地址有误","警告",JOptionPane.WARNING_MESSAGE);
        }catch (IllegalArgumentException e) { //端口值非法,发出提示
            JOptionPane.showMessageDialog(this,"端口值范围必须为0~65535","警告",JOptionPane.WARNING_MESSAGE);
        }
        catch  (IOException e) {
            JOptionPane.showMessageDialog(this,"无法连接至端口","警告",JOptionPane.WARNING_MESSAGE);
        }catch (Exception e){
            System.out.println(e.toString());
        }
    }
    private void sentmessage(){  //点击say按钮调用的方法
        if(readThread==null){   //先判断是否已经连接至服务器,若没有,提示并终止方法
            JOptionPane.showMessageDialog(this,"未连接无法发送信息","警告",JOptionPane.WARNING_MESSAGE);
            return;
        }
        try{
            out.writeUTF("Client: "+text3.getText()+"\n"); //发送信息至服务器
            text.append("Client: "+text3.getText()+"\n");  //客户端文本显示区添加刚发过的内容
            text3.setText(""); //清空输入栏
        }catch (IOException e){
            JOptionPane.showMessageDialog(this,"未知原因无法发送信息","警告",JOptionPane.WARNING_MESSAGE);
        }
    }
    class actionlistener implements ActionListener{
        public void actionPerformed(ActionEvent e){
            if(e.getSource()==button1) startserver(); //如果点击的按钮是connect(button1),调用startserver方法
            if(e.getSource()==button2) sentmessage(); //如果点击的按钮是say(button2),调用sentmessage方法
        }
    }
    class ReadThread extends Thread{  //读取数据的线程
        public void run(){
            while(true){
                try{
                    text.append(in.readUTF());  //读入服务器传入的信息,并显示到文本显示区
                }catch (IOException e) {
                    System.out.println(e.toString());
                }
            }

        }
    }
    public static void main(String[] args) {
        ClientFrame cf=new ClientFrame();
    }
}

卑微求赞

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值