news 2026/4/3 4:59:59

简单的tcp通讯-客户端实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
简单的tcp通讯-客户端实现

1定义静态变量

public class Constant {

public static final String SERVER_IP = "127.0.0.1";

public static final int SERVER_PORT = 6666;

}

2创建登录UI

import javax.swing.*;

import java.awt.*;

import java.io.DataOutputStream;

import java.net.Socket;

public class ChatEntryFrame extends JFrame {

private JTextField nicknameField;

private JButton enterButton;

private JButton cancelButton;

private Socket socket; // 记住当前客户端系统的通信管道

public ChatEntryFrame() {

setTitle("局域网聊天室");

setSize(350, 150);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

setLocationRelativeTo(null);

setResizable(false); // 禁止调整大小

// 设置背景颜色

getContentPane().setBackground(Color.decode("#F0F0F0"));

// 创建主面板并设置布局

JPanel mainPanel = new JPanel(new BorderLayout());

mainPanel.setBackground(Color.decode("#F0F0F0"));

add(mainPanel);

// 创建顶部面板

JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));

topPanel.setBackground(Color.decode("#F0F0F0"));

// 标签和文本框

JLabel nicknameLabel = new JLabel("昵称:");

nicknameLabel.setFont(new Font("楷体", Font.BOLD, 16));

nicknameField = new JTextField(10);

nicknameField.setFont(new Font("楷体", Font.PLAIN, 16));

nicknameField.setBorder(BorderFactory.createCompoundBorder(

BorderFactory.createMatteBorder(1, 1, 1, 1, Color.GRAY),

BorderFactory.createEmptyBorder(5, 5, 5, 5)

));

topPanel.add(nicknameLabel);

topPanel.add(nicknameField);

mainPanel.add(topPanel, BorderLayout.NORTH);

// 按钮面板

JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));

buttonPanel.setBackground(Color.decode("#F0F0F0"));

enterButton = new JButton("登录");

enterButton.setFont(new Font("楷体", Font.BOLD, 16));

enterButton.setBackground(Color.decode("#007BFF"));

enterButton.setForeground(Color.WHITE);

enterButton.setBorderPainted(false);

enterButton.setFocusPainted(false);

cancelButton = new JButton("取消");

cancelButton.setFont(new Font("楷体", Font.BOLD, 16));

cancelButton.setBackground(Color.decode("#DC3545"));

cancelButton.setForeground(Color.WHITE);

cancelButton.setBorderPainted(false);

cancelButton.setFocusPainted(false);

buttonPanel.add(enterButton);

buttonPanel.add(cancelButton);

mainPanel.add(buttonPanel, BorderLayout.SOUTH);

// 添加监听器

enterButton.addActionListener(e -> {

String nickname = nicknameField.getText(); // 获取昵称

nicknameField.setText("");

if (!nickname.isEmpty()) {

try {

login(nickname);

// 进入聊天室逻辑: 启动聊天界面。把昵称传给聊天界面。

new ClientChatFrame(nickname, socket);

this.dispose(); // 关闭登录窗口

} catch (Exception ex) {

ex.printStackTrace();

}

} else {

JOptionPane.showMessageDialog(this, "请输入昵称!");

}

});

cancelButton.addActionListener(e -> System.exit(0));

this.setVisible(true); // 显示窗口

}

public void login(String nickname) throws Exception {

// 立即发送登录消息给服务端程序。

// 1、创建Socket管道请求与服务端的socket链接

socket = new Socket(Constant.SERVER_IP, Constant.SERVER_PORT );

// 2、立即发送消息类型1 和自己的昵称给服务端

DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

dos.writeInt(1); // 消息类型 登录

dos.writeUTF(nickname);

dos.flush();

}

public static void main(String[] args) {

new ChatEntryFrame();

}

}

3创建聊天UI

import javax.swing.*;

import java.awt.*;

import java.io.DataOutputStream;

import java.net.Socket;

public class ClientChatFrame extends JFrame {

public JTextArea smsContent = new JTextArea(23, 50);

private JTextArea smsSend = new JTextArea(4, 40);

public JList<String> onLineUsers = new JList<>();

private JButton sendBn = new JButton("发送");

private Socket socket;

public ClientChatFrame() {

initView();

this.setVisible(true);

}

public ClientChatFrame(String nickname, Socket socket) {

this(); // 先调用上面的无参数构造器,初始化界面信息

// 初始化数据。

// 立马展示昵称到窗口

this.setTitle(nickname + "的聊天窗口");

this.socket = socket;

// 立即把客户端的这个Socket管道交给一个独立的线程专门负责读取客户端socket从服务端收到的在线人数更新数据或者群聊数据。

new ClientReaderThread(socket, this).start();

}

private void initView() {

this.setSize(800, 650);

this.setLayout(new BorderLayout(10, 10));

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭窗口,退出程序

this.setLocationRelativeTo(null); // 窗口居中

this.getContentPane().setBackground(Color.decode("#F8F9FA"));

// 统一字体样式

Font mainFont = new Font("微软雅黑", Font.PLAIN, 15);

Font listTitleFont = new Font("微软雅黑", Font.BOLD, 16);

// 消息内容框

smsContent.setFont(mainFont);

smsContent.setBackground(Color.WHITE);

smsContent.setEditable(false);

smsContent.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

smsContent.setLineWrap(true);

smsContent.setWrapStyleWord(true);

// 发送消息框

smsSend.setFont(mainFont);

smsSend.setBackground(Color.WHITE);

smsSend.setWrapStyleWord(true);

smsSend.setLineWrap(true);

smsSend.setBorder(BorderFactory.createCompoundBorder(

BorderFactory.createMatteBorder(1, 1, 1, 1, Color.decode("#CED4DA")),

BorderFactory.createEmptyBorder(8, 10, 8, 10)

));

// 在线用户列表区域

JPanel userListPanel = new JPanel(new BorderLayout(0, 8));

userListPanel.setBackground(Color.decode("#F8F9FA"));

userListPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

JLabel userListTitle = new JLabel("在线用户");

userListTitle.setFont(listTitleFont);

userListTitle.setForeground(Color.decode("#343A40"));

userListTitle.setHorizontalAlignment(SwingConstants.CENTER);

onLineUsers.setFont(mainFont);

onLineUsers.setBackground(Color.WHITE);

onLineUsers.setFixedCellWidth(150);

onLineUsers.setVisibleRowCount(15);

onLineUsers.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.decode("#CED4DA")));

JScrollPane userListScrollPane = new JScrollPane(onLineUsers);

userListScrollPane.setBorder(BorderFactory.createEmptyBorder());

userListScrollPane.setPreferredSize(new Dimension(160, 0));

userListPanel.add(userListTitle, BorderLayout.NORTH);

userListPanel.add(userListScrollPane, BorderLayout.CENTER);

// 底部发送区域

JPanel bottomPanel = new JPanel(new BorderLayout(10, 10));

bottomPanel.setBackground(Color.decode("#F8F9FA"));

bottomPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));

JScrollPane smsSendScrollPane = new JScrollPane(smsSend);

smsSendScrollPane.setBorder(BorderFactory.createEmptyBorder());

smsSendScrollPane.setPreferredSize(new Dimension(0, 100));

// 发送按钮

sendBn.setFont(mainFont);

sendBn.setBackground(Color.decode("#409EFF"));

sendBn.setForeground(Color.WHITE);

sendBn.setBorderPainted(false);

sendBn.setFocusPainted(false);

sendBn.setPreferredSize(new Dimension(100, 40));

sendBn.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));

JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));

btnPanel.setBackground(Color.decode("#F8F9FA"));

btnPanel.add(sendBn);

bottomPanel.add(smsSendScrollPane, BorderLayout.CENTER);

bottomPanel.add(btnPanel, BorderLayout.EAST);

// 中心消息区域

JScrollPane smsContentScrollPane = new JScrollPane(smsContent);

smsContentScrollPane.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.decode("#CED4DA")));

smsContentScrollPane.setPreferredSize(new Dimension(0, 0));

// 给发送按钮绑定点击事件

sendBn.addActionListener(e -> {

// 获取输入框中的内容

String msg = smsSend.getText();

// 清空输入框

smsSend.setText("");

// 发送消息

sendMsgToServer(msg);

});

// 组装整体布局

this.add(smsContentScrollPane, BorderLayout.CENTER);

this.add(bottomPanel, BorderLayout.SOUTH);

this.add(userListPanel, BorderLayout.EAST);

}

// 发送消息

private void sendMsgToServer(String msg) {

try {

// 1、从socket管道中得到一个特殊数据输出流

DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

// 2、把消息发送给服务端

dos.writeInt(2);

dos.writeUTF(msg);

dos.flush();

} catch (Exception e) {

e.printStackTrace();

}

}

public static void main(String[] args) {

new ClientChatFrame();

}

// 更新在线用户列表

public void updateOnlineUsers(String[] onLineNames) {

// 把这个线程读取到的在线用户名称展示到界面上

onLineUsers.setListData(onLineNames);

}

// 更新群聊消息

public void setMsgToWin(String msg) {

// 更新群聊消息到界面展示

smsContent.append(msg);

}

}

4创建新线程

import java.io.DataInputStream;

import java.net.Socket;

public class ClientReaderThread extends Thread{

private Socket socket;

private DataInputStream dis;

private ClientChatFrame win;

public ClientReaderThread( Socket socket, ClientChatFrame win) {

this.win = win;

this.socket = socket;

}

@Override

public void run() {

try {

// 接收的消息可能有很多种类型:1、在线人数更新的数据 2、群聊消息

dis = new DataInputStream(socket.getInputStream());

while (true) {

int type = dis.readInt(); // 1、2、3

switch (type){

case 1:

// 服务端发来的在线人数更新消息

updateClientOnLineUserList();

break;

case 2:

// 服务端发送来的群聊消息

getMsgToWin();

break;

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

private void getMsgToWin() throws Exception {

// 获取群聊消息

String msg = dis.readUTF();

win.setMsgToWin(msg);

}

// 更新客户端的在线用户列表

private void updateClientOnLineUserList() throws Exception {

// 1、读取有多少个在线用户

int count = dis.readInt();

// 2、循环控制读取多少个用户信息。

String[] names = new String[count];

for (int i = 0; i < count; i++) {

// 3、读取每个用户的信息

String nickname = dis.readUTF();

// 4、将每个用户的信息添加到数组

names[i] = nickname;

}

// 5、将集合中的数据展示到窗口上

win.updateOnlineUsers(names);

}

}

5创建一个新的类进行测试

public class App {

public static void main(String[] args) {

//启动程序

new ChatEntryFrame();

}

}

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/28 5:17:38

高可靠性UART通信模块设计:工业级方案全面讲解

以下是对您提供的技术博文进行 深度润色与专业重构后的版本 。本次优化严格遵循您的全部要求&#xff1a; ✅ 彻底去除AI痕迹&#xff0c;语言自然、老练、有工程师“实战口吻” ✅ 打破模板化结构&#xff0c;取消所有“引言/概述/总结”等刻板标题&#xff0c;代之以逻辑…

作者头像 李华
网站建设 2026/3/19 7:06:41

电商客服自动化实战:用gpt-oss-20b-WEBUI快速实现智能问答

电商客服自动化实战&#xff1a;用gpt-oss-20b-WEBUI快速实现智能问答 在电商运营中&#xff0c;客服响应速度与服务质量直接决定用户留存率和转化率。一家日均咨询量超5000次的中型服饰品牌曾向我们反馈&#xff1a;人工客服平均响应时间83秒&#xff0c;重复问题占比达67%&a…

作者头像 李华
网站建设 2026/4/2 0:33:58

Cute_Animal_For_Kids_Qwen_Image参数详解:提示词优化实战手册

Cute_Animal_For_Kids_Qwen_Image参数详解&#xff1a;提示词优化实战手册 你是不是也遇到过这样的情况&#xff1a;给孩子生成一张“小兔子”&#xff0c;结果出来一只毛发凌乱、眼神呆滞、背景灰暗的图&#xff1f;或者输入“穿裙子的熊猫”&#xff0c;AI却画出一只站在电线…

作者头像 李华
网站建设 2026/3/31 6:02:58

Qwen-Image-Layered开箱即用:Docker一键部署指南

Qwen-Image-Layered开箱即用&#xff1a;Docker一键部署指南 你是否遇到过这样的问题&#xff1a;刚生成一张满意的AI图片&#xff0c;想只把背景换成星空、把人物衣服调成深蓝、再给LOGO加个发光效果——结果一编辑&#xff0c;整个人物边缘发虚&#xff0c;光影错乱&#xf…

作者头像 李华
网站建设 2026/3/31 17:02:29

Qwen3-Embedding-4B资源隔离:多任务调度部署方案

Qwen3-Embedding-4B资源隔离&#xff1a;多任务调度部署方案 1. Qwen3-Embedding-4B&#xff1a;面向生产环境的高精度文本嵌入底座 Qwen3-Embedding-4B不是一款“能跑就行”的通用嵌入模型&#xff0c;而是专为工业级语义服务设计的轻量级高性能文本嵌入引擎。它属于Qwen3 E…

作者头像 李华
网站建设 2026/3/31 3:06:59

YOLOv9推理批处理:source目录批量图像检测实战

YOLOv9推理批处理&#xff1a;source目录批量图像检测实战 你是不是也遇到过这样的情况&#xff1a;手头有一整个文件夹的监控截图、商品照片或工业质检图像&#xff0c;想快速跑一遍YOLOv9检测&#xff0c;却卡在“怎么一次处理几十张图”这一步&#xff1f;官方教程里只给了单…

作者头像 李华