Java实现简易TCP客户端、服务器端通信程序

本学期计算机网络课程要求完成一个TCP和一个UDP的通信程序,我完成了功能的简单实现,下面讲讲我的TCP程序的实现。

效果展示

连接成功
互发消息

以下是具体实现过程:

一、项目结构

项目结构

下面说说每个类的具体作用:
TCPClient:TCP客户端的核心代码部分;
TCPClientFrame:TCP客户端的界面搭建;
TCPServer:TCP服务器端的核心代码部分;
TCPServerFrame:TCP服务器端的界面搭建;
TCPSend:客户端和服务器端发送信息的功能实现;
ReminderTextAdapter:网上查阅的代码,非核心内容实现部分,主要用于灰色提示字hint功能的实现(swing中的实现方法不太熟悉);

二、完整代码

1.TCPClient

代码如下:

package tcpCommunication;

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

public class TCPClient implements ActionListener, Runnable {
    private TCPClientFrame clientFrame;
    private Socket socket;
    private Thread thread = null;
    private DataInputStream inFromServer;
    private DataOutputStream outToServer;
    
    public TCPClient() {
        JPanel panel = new JPanel();

        clientFrame = new TCPClientFrame("TCPClient");
        clientFrame.add(panel);

        clientFrame.placeComponents(panel);
        clientFrame.setVisible(true);

        clientFrame.getConnect().addActionListener(e -> {
            try {
                //host:"127.0.0.1"
                String host = clientFrame.getIpField().getText();
                //port:6666
                int port = Integer.parseInt(clientFrame.getPortField().getText());
                socket = new Socket(host, port);
                clientFrame.getTextArea().append("[Connect] : Connect…\n");

                inFromServer = new DataInputStream(socket.getInputStream());
                outToServer = new DataOutputStream(socket.getOutputStream());
                //new TCPSend(socket, "客户端").sendMessage();

                thread = new Thread(this);
                thread.setPriority(Thread.MIN_PRIORITY);
                thread.start();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        });

        clientFrame.getTransmit().addActionListener(this);
        System.out.println("TCP客户端准备就绪\n");
    }

    public static void main(String[] args) {
        new TCPClient();
    }

    //向服务器端发送数据
    @Override
    public void actionPerformed(ActionEvent e) {
        String send = clientFrame.getSendField().getText();
        new TCPSend(send, outToServer, clientFrame.getTextArea(),
                "Client").sendMessages();
    }

    //使用线程处理客户端接收服务器端的数据
    @Override
    public void run() {
        while (true) {
            try {
                clientFrame.getTextArea().append("[Server send] : " + inFromServer.readUTF() + "\n");
                Thread.sleep(100);
            } catch (IOException | InterruptedException e) {
                //e.printStackTrace();
                System.out.println("客户端与服务器连接中断\n");
                break;
            }
        }
    }
}

2.TCPClientFrame

代码如下:

package tcpCommunication;

import udpCommunication.ReminderTextAdapter;

import javax.swing.*;
import java.awt.*;

public class TCPClientFrame extends JFrame {
    private static JTextField ipField;
    private static JTextField portField;
    private static JTextField sendField;
    private static JTextArea textArea;
    private static JButton connect;
    private static JButton transmit;

    public TCPClientFrame(String title) {
        setSize(700, 480);
        setLocationRelativeTo(null);//居中显示
        setResizable(false);//设置不允许改变窗体大小
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle(title);
    }

    public JTextField getIpField() {
        return ipField;
    }

    public JTextField getPortField() {
        return portField;
    }

    public JTextField getSendField() {
        return sendField;
    }

    public JTextArea getTextArea() {
        return textArea;
    }

    public JButton getConnect() {
        return connect;
    }

    public JButton getTransmit() {
        return transmit;
    }

    public void placeComponents(JPanel panel) {
        panel.setLayout(null);
        Font font1 = new Font("宋体", Font.BOLD, 18);
        Font font2 = new Font("宋体", Font.PLAIN, 18);

        //创建JLabel
        JLabel ip = new JLabel("IP");
        ip.setFont(font1);//设置JLabel的字体
        ip.setBounds(105, 35, 120, 38);
        panel.add(ip);

        JLabel port = new JLabel("Port");
        port.setFont(font1);
        port.setBounds(105, 80, 120, 38);
        panel.add(port);

        JLabel send = new JLabel("Send");
        send.setFont(font1);
        send.setBounds(105, 125, 120, 38);
        panel.add(send);

        JLabel text = new JLabel("Text");
        text.setFont(font1);
        text.setBounds(105, 170, 120, 38);
        panel.add(text);

        //创建文本域
        ipField = new JTextField(30);
        ipField.setFont(font2);
        ipField.addFocusListener(new tcpCommunication.ReminderTextAdapter(ipField, "默认:127.0.0.1"));
        ipField.setBounds(180, 35, 380, 38);
        panel.add(ipField);

        portField = new JTextField(30);
        portField.setFont(font2);
        portField.addFocusListener(new ReminderTextAdapter(portField, "port:"));
        portField.setBounds(180, 80, 380, 38);
        panel.add(portField);

        sendField = new JTextField(30);
        sendField.setFont(font2);
        sendField.addFocusListener(new ReminderTextAdapter(sendField, "请输入要发送的信息:"));
        sendField.setBounds(180, 125, 380, 38);
        panel.add(sendField);

        textArea = new JTextArea();
        textArea.setFont(font2);
        textArea.setBounds(180, 170, 380, 170);
        textArea.setEditable(false);
        textArea.setLineWrap(false);
        panel.add(textArea);

        //给textArea添加滚动条
        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setBounds(180, 170, 380, 170);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        panel.add(scrollPane);
        scrollPane.setViewportView(textArea);

        //添加两个按钮
        connect = new JButton("连接");
        connect.setFont(font1);
        connect.setBounds(140, 360, 115, 40);
        panel.add(connect);

        transmit = new JButton("发送");
        transmit.setFont(font1);
        transmit.setBounds(440, 360, 115, 40);
        panel.add(transmit);
    }

}

3.TCPServer

代码如下:

package tcpCommunication;

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

public class TCPServer implements ActionListener, Runnable {
    private TCPServerFrame serverFrame;
    private ServerSocket server;
    private Socket socket;
    private Thread thread = null;
    private DataInputStream inFromClient;
    private DataOutputStream outToClient;

    public TCPServer() {
        serverFrame = new TCPServerFrame("TCPServer");
        JPanel panel = new JPanel();
        serverFrame.add(panel);

        serverFrame.placeComponents(panel);
        serverFrame.setVisible(true);

        //port:6666
        serverFrame.getMonitor().addActionListener(e -> {
            try {
                int port = Integer.parseInt(serverFrame.getPortField().getText());
                server = new ServerSocket(port);
                serverFrame.getTextArea().append("[Listen] : Listen…\n");
                //获取客户端的socket
                socket = server.accept();
                serverFrame.getTextArea().append("[Accept] : Accept OK.\n");
                inFromClient = new DataInputStream(socket.getInputStream());
                outToClient = new DataOutputStream(socket.getOutputStream());

                thread = new Thread(this);
                //创建子线程处理客户端输入信息
                //new TCPServerThread(socket).start();
                thread.setPriority(Thread.MIN_PRIORITY);
                thread.start();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        });

        serverFrame.getTransmit().addActionListener(this);
        System.out.println("TCP服务器准备就绪\n");
    }

    public static void main(String[] args) {
        new TCPServer();
    }

    //向客户端发送数据
    @Override
    public void actionPerformed(ActionEvent e) {
        String send = serverFrame.getSendField().getText();
        new TCPSend(send, outToClient, serverFrame.getTextArea(),
                "Server").sendMessages();
    }

    //使用线程处理服务器端接收客户端的数据
    @Override
    public void run() {
        while (true) {
            try {
                serverFrame.getTextArea().append("[Client send] : " + inFromClient.readUTF() + "\n");
                Thread.sleep(100);
            } catch (IOException | InterruptedException e) {
                //e.printStackTrace();
                System.out.println("服务器与客户端连接中断\n");
                break;
            }
        }

    }
}

4.TCPServerFrame

代码如下:

package tcpCommunication;

import udpCommunication.ReminderTextAdapter;

import javax.swing.*;
import java.awt.*;

public class TCPServerFrame extends JFrame {
    private static JTextField portField;
    private static JTextField sendField;
    private static JTextArea textArea;
    private static JButton monitor;
    private static JButton transmit;

    public TCPServerFrame(String title) {
        setSize(700, 480);
        setLocationRelativeTo(null);//居中显示
        setResizable(false);//设置不允许改变窗体大小
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle(title);
    }

    public JTextField getPortField() {
        return portField;
    }

    public JTextField getSendField() {
        return sendField;
    }

    public JTextArea getTextArea() {
        return textArea;
    }

    public JButton getMonitor() {
        return monitor;
    }

    public JButton getTransmit() {
        return transmit;
    }

    public void placeComponents(JPanel panel) {
        panel.setLayout(null);

        Font font1 = new Font("宋体", Font.BOLD, 18);
        Font font2 = new Font("宋体", Font.PLAIN, 18);

        //创建JLabel
        JLabel port = new JLabel("Port");
        port.setFont(font1);
        port.setBounds(105, 45, 120, 38);
        panel.add(port);

        JLabel send = new JLabel("Send");
        send.setFont(font1);
        send.setBounds(105, 100, 120, 38);
        panel.add(send);

        JLabel text = new JLabel("Text");
        text.setFont(font1);
        text.setBounds(105, 165, 120, 38);
        panel.add(text);

        //创建文本域
        portField = new JTextField(30);
        portField.setFont(font2);
        portField.addFocusListener(new ReminderTextAdapter(portField, "port:"));
        portField.setBounds(180, 45, 380, 38);
        panel.add(portField);

        sendField = new JTextField(30);
        sendField.setFont(font2);
        sendField.addFocusListener(new ReminderTextAdapter(sendField, "请输入要发送的信息:"));
        sendField.setBounds(180, 100, 380, 38);
        panel.add(sendField);

        textArea = new JTextArea();
        textArea.setFont(font2);
        textArea.setBounds(180, 160, 380, 170);
        textArea.setEditable(false);
        textArea.setLineWrap(false);
        panel.add(textArea);

        //给textArea添加滚动条
        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setBounds(180, 160, 380, 170);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        panel.add(scrollPane);
        scrollPane.setViewportView(textArea);

        //添加两个按钮
        monitor = new JButton("监听");
        monitor.setFont(font1);
        monitor.setBounds(140, 360, 115, 40);
        panel.add(monitor);

        transmit = new JButton("发送");
        transmit.setFont(font1);
        transmit.setBounds(440, 360, 115, 40);
        panel.add(transmit);
    }
}

5.TCPSend

代码如下:

package tcpCommunication;

import javax.swing.*;
import java.io.DataOutputStream;
import java.io.IOException;

public class TCPSend {
    private String send;
    private DataOutputStream dataOutputStream;
    private JTextArea textArea;
    private String sendObject;

    public TCPSend(String send, DataOutputStream dataOutputStream, JTextArea textArea, String sendObject) {
        this.send = send;
        this.dataOutputStream = dataOutputStream;
        this.textArea = textArea;
        this.sendObject = sendObject;
    }

    public void sendMessages() {
        if (send.length() > 0) {
            try {
                dataOutputStream.writeUTF(send);
                dataOutputStream.flush();
                textArea.append("\t\t     [" + sendObject + " send] : " + send + "\n");
            } catch (IOException ex) {
                textArea.append("Your message : “" + send + "”failed to send!\n");
            }
        }
    }

}

6.ReminderTextAdapter(参考别人的,非原创)

代码如下:

package tcpCommunication;

import javax.swing.*;
import java.awt.*;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;

public class ReminderTextAdapter extends FocusAdapter {
    //JTextField提示文字通用方法
    JTextField textField;
    String reminderString;

    //初始化
    public ReminderTextAdapter(JTextField textField, String reminderString) {
        this.textField = textField;
        this.reminderString = reminderString;
    }

    //焦点获得
    @Override
    public void focusGained(FocusEvent e) {
        String tempString = textField.getText();
        //String tempString = this.getText();
        if (tempString.equals(reminderString)) {
            textField.setText("");
            textField.setForeground(Color.BLACK);
        }
    }

    //焦点失去
    @Override
    public void focusLost(FocusEvent e) {
        String tempString = textField.getText();
        if (tempString.equals("")) {
            textField.setForeground(Color.GRAY);
            textField.setText(reminderString);
        }
    }

}

总结

该项目简单的实现了TCP客户端和服务器端的通信,但是功能比较简单,页面也比较简洁,没有实现多个客户端互聊的功能等,还有待完善。

CSDN文章链接:https://blog.csdn.net/twj1248445531/article/details/110947510(这是我CSDN里写的,有目录,简书好像不行,不支持网页标签)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容