苟哥的笔记本
首页
文章归档
关于
文章归档
关于
首页
编程
正文
基于Swing的一对一聊天程序
苟哥
2019-12-28 AM
2709℃
0条
## 前言 在另一篇文章《[使用Java Socket演示客户端与服务端的一问一答](http://www.i366211.com/archives/59/ "使用Java Socket演示客户端与服务端的一问一答")》中有着重提到该文演示的客户端与服务端的通信是一问一答式的,但是当时没有解答原因是什么。这篇文章准备演示一个简单的自由沟通式聊天程序,因此我们要先明白之前的客户端与服务端只能一问一答的原因。对线程有一定了解的,其实可以很快想到原因,因为客户端、服务端的接收和发送都在主线程中,而同一个线程中同一时间只能处理接收或发送的任务。 为了实现同时收发消息,那就要做个特殊处理——把接收和发送分别放在不同的线程中进行。 ## 思路 1. 实现效果 我们先来看看最终程序运行后的效果(如下图1),由结果来反推我们是如何一步一步实现的: ![socket自由聊天.png](http://images.kuryun.com/blog/typecho/socket自由聊天.png) (图1) 1. 从程序运行结果可以看到聊天界面是由swing构建的,整个界面由以下元素组成: - 一个主窗体(JFrame) - 一个顶部panel(JPanel) - 顶部panel加入一个label(JLabel),显示对方的名称 - 主体部分是一个滚动pane(JScrollPane) - 滚动pane增加一个多行文本框textarea(JTextArea),用于显示聊天内容 - 底部增加一个panel(Jpanel) - 底部panel上增加一个输入内容的label(JLabel)和text(JTextField) - 底部panel上增加一个发送按钮(JButton),并设计按钮点击事件 3.socket实现逻辑: - 建立连接 - 客户端使用主线程发送消息,创建一个子线程用来接收消息 - 服务端使用主线程发送消息,创建一个子线程用来接收消息 通过以上设计方案,就可以快速使用代码实现了。 ## 代码实现 Server.java: ```java package socket; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.List; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; public class Server { static ServerSocket ss; static Socket s; static JTextArea messageBox; public static void main(String[] args) { try { ss = new ServerSocket(8888); System.out.println("服务已建立,等待客户端消息"); s = ss.accept(); chat(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 聊天框 */ private static void chat() { JFrame f = new JFrame("SmileChat"); f.setSize(500, 400); f.setLocation(900, 200); f.setLayout(new BorderLayout()); // 顶部文本条 JPanel p = new JPanel(); JLabel l = new JLabel("Client"); p.add(l); // 使用滚动面板,表格放到面板上 messageBox = new JTextArea(); messageBox.setPreferredSize(new Dimension(200, 150)); messageBox.setLineWrap(true); // 设置自动换行 messageBox.setEditable(false); // 因为是展示聊天内容,所以不允许编辑 JScrollPane sp = new JScrollPane(messageBox); JPanel bottomP = new JPanel(); bottomP.setLayout(new FlowLayout()); JLabel tlMsg = new JLabel("输入内容:"); JTextField tfMsg = new JTextField(""); tfMsg.setPreferredSize(new Dimension(200, 30)); JButton sendB = new JButton("发送"); sendB.setPreferredSize(new Dimension(80, 30)); bottomP.add(tlMsg); bottomP.add(tfMsg); bottomP.add(sendB); f.add(p, BorderLayout.NORTH); f.add(sp, BorderLayout.CENTER); f.add(bottomP, BorderLayout.SOUTH); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); tfMsg.grabFocus(); // 登陆事件 sendB.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String msg = tfMsg.getText(); if (msg.equals("")) { JOptionPane.showMessageDialog(f, "不能发送空消息"); return; } try { OutputStream os = s.getOutputStream(); // socket输出流。将控制台信息数据传给对方 PrintWriter pw = new PrintWriter(new OutputStreamWriter(os)); messageBox.append("我:" + msg + "\n"); pw.println("Server" + ":" + msg); pw.flush(); //清空对话框 tfMsg.setText(""); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } }); // 启动接受消息线程 new ReceiveThread(s, messageBox).start(); } } ``` Client.java ```java package socket; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; public class Client { static Socket s; static JTextArea messageBox; public static void main(String[] args) { try { s = new Socket("127.0.0.1", 8888); chat(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 聊天框 */ private static void chat() { JFrame f = new JFrame("SmileChat"); f.setSize(500, 400); f.setLocation(200, 200); f.setLayout(new BorderLayout()); //顶部文本条 JPanel p = new JPanel(); JLabel l = new JLabel("Server"); p.add(l); // 使用滚动面板,表格放到面板上 messageBox = new JTextArea(); messageBox.setPreferredSize(new Dimension(200, 150)); messageBox.setLineWrap(true); //设置自动换行 messageBox.setEditable(false); //因为是展示聊天内容,所以不允许编辑 JScrollPane sp = new JScrollPane(messageBox); JPanel bottomP = new JPanel(); bottomP.setLayout(new FlowLayout()); JLabel tlMsg = new JLabel("输入内容:"); JTextField tfMsg = new JTextField(""); tfMsg.setPreferredSize(new Dimension(200, 30)); JButton sendB = new JButton("发送"); sendB.setPreferredSize(new Dimension(80, 30)); bottomP.add(tlMsg); bottomP.add(tfMsg); bottomP.add(sendB); f.add(p, BorderLayout.NORTH); f.add(sp, BorderLayout.CENTER); f.add(bottomP, BorderLayout.SOUTH); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); tfMsg.grabFocus(); // 登陆事件 sendB.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String msg = tfMsg.getText(); if (msg.equals("")) { JOptionPane.showMessageDialog(f, "不能发送空消息"); return; } try { OutputStream os = s.getOutputStream(); // socket输出流。将控制台信息数据传给对方 PrintWriter pw = new PrintWriter(new OutputStreamWriter(os)); messageBox.append("我:" + msg + "\n"); pw.println("Client" + ":" + msg); pw.flush(); //清空对话框 tfMsg.setText(""); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } }); // 启动接受消息线程 new ReceiveThread(s, messageBox).start(); } } ``` ReceiveThread.java: ```java package socket; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.Socket; import javax.swing.JTextArea; public class ReceiveThread extends Thread { private Socket s; static String receiveMsg = ""; static JTextArea messageBox; public ReceiveThread(Socket s, JTextArea ta) { this.s = s; this.messageBox = ta; } public void run() { try { InputStream is = s.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); // 读取客户端过来的流 while(true){ receiveMsg = br.readLine(); messageBox.append(receiveMsg + "\n"); //System.out.println(receiveMsg); //System.out.println("请输入:"); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } ``` ## TODO 目前仅仅是实现了简单的一对一聊天功能,真正的聊天程序肯定比这个复杂多了,大家可以发挥聪明才智去设计并实现自己想要的聊天程序,例如可以增加以下几个功能: - 扩展内容的类型,例如增加图片、音频、视频等 - 增加登录、注册板块,从而控制权限 - 升级为多人聊天,并增加好友管理的板块 - 保存历史消息
标签:
Java
,
Swing
,
聊天程序
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
http://www.i366211.com/archives/63/
上一篇
使用Java Socket演示客户端与服务端的一问一答
下一篇
讨论多线程synchronized的用法
取消回复
评论啦~
提交评论
栏目分类
软件安装
10
开发工具
8
算法
2
测试
1
架构
3
填坑记
2
开源
6
科普
6
私域
2
读书笔记
4
编程
48
运营
3
管理
1
标签云
算法
C程序设计语言
C语言
Java
mysql
PHP
ffmpeg
golang
VueJs
脚手架
VueJs实战项目
Intellij IDEA
Centos7
Hyperf
抖音运营
杰克韦尔奇
跌荡一百年
生成海量测试数据
企业管理
习题2-3
习题2-4
习题2-6
异常分类
File
习题2-7
习题2-8
习题2-9
习题3-3
习题3-4
习题3-5
友情链接
申请
SaaS引擎
机器人框架
京东捡漏