当前位置: 首页 > news >正文

简单的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.jsqmd.com/news/291621/

相关文章:

  • Llama3-8B加载失败?显存优化3步解决实战指南
  • 开源人像增强模型GPEN实战:从零开始搭建修复系统完整指南
  • verl灵活并行化实战:不同规模GPU集群适配指南
  • Qwen2.5-0.5B如何用于代码补全?IDE插件开发案例
  • 2024年AI艺术创作入门必看:NewBie-image-Exp0.1完整使用指南
  • 关于可变参数的笔记
  • EVOH九层共挤哪家好?2026安徽九层共挤吹膜厂家推荐盘点
  • 如何实现远程访问?DeepSeek-R1 Web服务外网暴露方案
  • 2026年襄阳口碑装修团队深度评测与联系指南
  • YOLOv9镜像适合团队协作吗?落地经验分享
  • 电商客服自动化实战:用gpt-oss-20b-WEBUI快速实现智能问答
  • Qwen All-in-One日志审计:合规性记录部署指南
  • cv_unet_image-matting实战案例:社交媒体头像自动化生成流程
  • 实时操作系统中erase任务调度优化
  • fft npainting lama正常关闭方式:Ctrl+C终止进程教程
  • Arduino安装进阶技巧:自定义库路径配置方法详解
  • Sambert在教育场景的应用:AI教师语音生成部署完整指南
  • verl多任务训练:共享模型结构的部署实践案例
  • 用Glyph构建企业知识库,支持超长文档检索
  • Qwen2.5-0.5B与DeepSeek-Coder对比:代码生成评测
  • Java毕设项目推荐-基于springboot的术后护工服务管理便捷服务系统【附源码+文档,调试定制服务】
  • 实测YOLOv9镜像性能,结果令人惊喜
  • Java毕设项目推荐-基于springboot的电信卡智慧通讯业务办理3D可视化平台【附源码+文档,调试定制服务】
  • 模拟电子技术基础:电流检测电阻选型与布局操作指南
  • Qwen3-1.7B性能优化教程:GPU算力高效利用的5个关键步骤
  • 开源大模型趋势解读:YOLO26弹性部署成新主流
  • cv_unet_image-matting降本部署案例:低成本GPU方案节省费用60%
  • llmdoc: 解决AI Coding的最后100米
  • 【计算机毕业设计案例】基于Web的智能选择系统基于Web的智能选择系统(程序+文档+讲解+定制)
  • BSHM模型支持绝对路径输入?实测成功