简单的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();

}

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1207855.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Llama3-8B加载失败?显存优化3步解决实战指南

Llama3-8B加载失败&#xff1f;显存优化3步解决实战指南 1. 问题现场&#xff1a;为什么你的Llama3-8B总在启动时崩溃&#xff1f; 你兴冲冲下载了 Meta-Llama-3-8B-Instruct&#xff0c;配置好环境&#xff0c;敲下 vllm serve --model meta-llama/Meta-Llama-3-8B-Instruct…

开源人像增强模型GPEN实战:从零开始搭建修复系统完整指南

开源人像增强模型GPEN实战&#xff1a;从零开始搭建修复系统完整指南 你有没有遇到过这样的情况&#xff1a;翻出一张老照片&#xff0c;人脸模糊、噪点多、细节丢失&#xff0c;想修复却无从下手&#xff1f;或者手头有一张低分辨率人像图&#xff0c;想放大又怕失真、发虚、…

verl灵活并行化实战:不同规模GPU集群适配指南

verl灵活并行化实战&#xff1a;不同规模GPU集群适配指南 1. verl 是什么&#xff1a;为大模型后训练量身打造的强化学习框架 你可能已经用过 PPO、DPO 或其他 RL 方法微调过语言模型&#xff0c;但有没有遇到过这样的问题&#xff1a;训练流程像一锅乱炖——Actor、Critic、…

Qwen2.5-0.5B如何用于代码补全?IDE插件开发案例

Qwen2.5-0.5B如何用于代码补全&#xff1f;IDE插件开发案例 1. 为什么小模型也能做好代码补全&#xff1f; 你可能第一反应是&#xff1a;0.5B参数的模型&#xff0c;连“大”都谈不上&#xff0c;怎么敢碰代码补全这种对准确性和上下文理解要求极高的任务&#xff1f; 其实&…

2024年AI艺术创作入门必看:NewBie-image-Exp0.1完整使用指南

2024年AI艺术创作入门必看&#xff1a;NewBie-image-Exp0.1完整使用指南 你是不是也试过在AI绘画工具里反复调整关键词&#xff0c;结果生成的角色不是少只手就是头发飘到外太空&#xff1f;或者想画两个角色同框&#xff0c;却总是一个清晰一个糊成马赛克&#xff1f;别急——…

关于可变参数的笔记

一、核心概述可变参数&#xff08;Variable Arguments&#xff09;是 Java 5 引入的特性&#xff0c;允许方法接收任意数量的同类型参数&#xff0c;本质是语法糖&#xff0c;底层会自动转换为数组处理。核心特点● 方法参数列表中&#xff0c;可变参数只能有一个&#xff1b;●…

EVOH九层共挤哪家好?2026安徽九层共挤吹膜厂家推荐盘点

EVOH九层共挤哪家好?2026安徽九层共挤吹膜厂家推荐。九层共挤吹膜技术是通过多个模头将单一或多种树脂熔化后共挤出成膜的工艺,无需黏合剂,避免了溶剂残留问题。其中EVOH(乙烯/乙烯醇共聚物)作为核心阻隔材料,凭…

如何实现远程访问?DeepSeek-R1 Web服务外网暴露方案

如何实现远程访问&#xff1f;DeepSeek-R1 Web服务外网暴露方案 你已经成功在本地服务器上跑起了 DeepSeek-R1-Distill-Qwen-1.5B 的 Web 服务&#xff0c;界面也打开了&#xff0c;输入提示词后模型能流畅输出数学推导、写 Python 脚本、甚至帮你理清复杂逻辑链——但问题来了…

2026年襄阳口碑装修团队深度评测与联系指南

在消费升级与品质生活需求日益凸显的今天,家庭装修已远不止于满足基本的居住功能,更是承载着人们对美好生活的向往与个性化审美的表达。然而,装修市场信息不对称、施工质量参差不齐、过程管理混乱等痛点长期困扰着广…

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

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

YOLOv9镜像适合团队协作吗?落地经验分享

YOLOv9镜像适合团队协作吗&#xff1f;落地经验分享 在目标检测工程实践中&#xff0c;我们常面临一个尴尬现实&#xff1a;模型结构越先进&#xff0c;落地门槛反而越高。YOLOv9作为2024年提出的新型目标检测架构&#xff0c;凭借可编程梯度信息&#xff08;PGI&#xff09;和…

Qwen All-in-One日志审计:合规性记录部署指南

Qwen All-in-One日志审计&#xff1a;合规性记录部署指南 1. 为什么日志审计需要“智能记录”而不是“简单存档” 你有没有遇到过这样的情况&#xff1a;系统每天生成上万行日志&#xff0c;但真正出问题时&#xff0c;翻了半小时才找到那条关键报错&#xff1f;或者安全审计…

cv_unet_image-matting实战案例:社交媒体头像自动化生成流程

cv_unet_image-matting实战案例&#xff1a;社交媒体头像自动化生成流程 1. 为什么需要这个流程&#xff1f;——从手动修图到一键出图的转变 你有没有遇到过这样的场景&#xff1a;朋友临时要发一条朋友圈&#xff0c;急着换新头像&#xff0c;但手边只有一张带背景的自拍照…

实时操作系统中erase任务调度优化

以下是对您提供的技术博文进行 深度润色与结构重构后的版本 。本次优化严格遵循您的全部要求&#xff1a; ✅ 彻底去除AI痕迹&#xff0c;语言更贴近资深嵌入式工程师的自然表达 ✅ 摒弃模板化标题&#xff08;如“引言”“总结”&#xff09;&#xff0c;全文以逻辑流驱动…

fft npainting lama正常关闭方式:Ctrl+C终止进程教程

FFT NPainting LaMa图像修复系统&#xff1a;正常关闭服务的正确方式 在使用FFT NPainting LaMa图像修复系统时&#xff0c;很多用户会遇到一个看似简单却容易被忽略的问题&#xff1a;如何安全、干净地停止正在运行的WebUI服务&#xff1f; 很多人习惯性地直接关闭终端窗口&a…

Arduino安装进阶技巧:自定义库路径配置方法详解

以下是对您提供的博文内容进行 深度润色与结构重构后的专业级技术文章 。全文已彻底去除AI痕迹&#xff0c;强化了人类专家口吻、实战经验沉淀与教学逻辑&#xff0c;同时严格遵循您的所有格式与风格要求&#xff08;无模板化标题、无总结段、自然收尾、口语化但不失严谨、关…

Sambert在教育场景的应用:AI教师语音生成部署完整指南

Sambert在教育场景的应用&#xff1a;AI教师语音生成部署完整指南 1. 为什么教育场景特别需要AI语音教师 你有没有遇到过这样的情况&#xff1a;录一节10分钟的微课&#xff0c;光是反复重录语音就花了近一个小时&#xff1f;或者想给不同年级的学生准备差异化讲解音频&#…

verl多任务训练:共享模型结构的部署实践案例

verl多任务训练&#xff1a;共享模型结构的部署实践案例 1. verl 是什么&#xff1f;一个为LLM后训练而生的强化学习框架 你可能已经听说过用强化学习&#xff08;RL&#xff09;来优化大语言模型——比如让模型更听话、更安全、更符合人类偏好。但真正把 RL 落地到千卡级 LL…

用Glyph构建企业知识库,支持超长文档检索

用Glyph构建企业知识库&#xff0c;支持超长文档检索 在企业日常运营中&#xff0c;知识管理始终是个“看似简单、实则棘手”的难题&#xff1a;技术文档动辄上百页PDF&#xff0c;产品手册更新频繁&#xff0c;合同条款密密麻麻&#xff0c;会议纪要堆叠如山……当员工需要快…

Java毕设项目推荐-基于springboot的术后护工服务管理便捷服务系统【附源码+文档,调试定制服务】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…