第98题JAVA高级技术-网络编程17(简易聊天室12:实现客户端一对一聊天)
Posted 小虚竹
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第98题JAVA高级技术-网络编程17(简易聊天室12:实现客户端一对一聊天)相关的知识,希望对你有一定的参考价值。
回城传送–》《JAVA筑基100例》
文章目录
零、前言
今天是学习 JAVA语言 打卡的第98天,每天我会提供一篇文章供群成员阅读( 不需要订阅付钱 ),读完文章之后,按解题思路,自己再实现一遍。在小虚竹JAVA社区 中对应的 【打卡贴】打卡,今天的任务就算完成了。
因为大家都在一起学习同一篇文章,所以有什么问题都可以在群里问,群里的小伙伴可以迅速地帮到你,一个人可以走得很快,一群人可以走得很远,有一起学习交流的战友,是多么幸运的事情。
学完后,自己写篇学习报告的博客,可以发布到小虚竹JAVA社区 ,供学弟学妹们参考。
我的学习策略很简单,题海策略+ 费曼学习法。如果能把这100题都认认真真自己实现一遍,那意味着 JAVA语言 已经筑基成功了。后面的进阶学习,可以继续跟着我,一起走向架构师之路。
一、题目描述
题目实现:不同的客户端之间需要进行通信,一个客户端与指定的另一客户端进行通信,实现一对一聊天功能。
实现一个客户端与指定的另一客户端进行通信,运行程序,服务器启动后,启动3个客户端程序,分别以小小,虚虚,竹竹,登录 ,然后在左侧的用户列表中选择接收信息用户,输入聊天信息,发送到目标用户。
二、解题思路
创建一个服务类:ClientOneToOneServerFrame,继承JFrame类
定义ServerThread线程类,用于为客户端添加用户列表。有一部分代码用于转发客户端发送的消息。
创建一个客户端类:ClientOneToOneClientFrame,继承JFrame类
定义ClientThread线程类,用于对接收到服务器的信息,进行处理。如果是登录用户,就添加到用户列表中。
如果是消息,就追加到文本域中。
技术重点:
在服务器端通过线程对客户端发送的信息进行监听,并对登录用户和消息分别进行处理。如果是登录用户,就将所有用户添加到客户端的用户列表中;如果是消息,就转发给指定的用户;客户端则通过线程对接收到的信息进行处理,如果是登录用户就添加到用户列表中,如果是消息就追加到文本域中。
(1)在服务器端创建线程类ServerThread,用于对登录用户和消息分别进行处理。如果是登录用户,就将所有用户添加到客户端的用户列表中;如果是消息就转发给指定的用户。
(2)在客户端创建线程类ClientThread,用于对接收到的信息进行处理,如果是登录用户就添加到用户列表中,如果是消息就追加到文本域中。
启动多个客户端:
1、把项目打成jar包:利用maven 的clean install
会在target目录下生成jar包
2、进入target目录,使用java -cp的命令运行指定的类
java -cp 命令中 cp 指的就是classpath。使用该命令可以运行jar中的某个指定的类(要包含全路径的包名)
进入cmd命令模式
运行服务端
java -cp basics98-1.0-SNAPSHOT.jar com.xiaoxuzhu.ClientOneToOneServerFrame
运行多个客户端
java -cp basics98-1.0-SNAPSHOT.jar com.xiaoxuzhu.ClientOneToOneClientFrame
三、代码详解
ClientOneToOneServerFrame
package com.xiaoxuzhu;
import java.awt.BorderLayout;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
/**
* Description:
*
* @author xiaoxuzhu
* @version 1.0
*
* <pre>
* 修改记录:
* 修改后版本 修改人 修改日期 修改内容
* 2022/6/5.1 xiaoxuzhu 2022/6/5 Create
* </pre>
* @date 2022/6/5
*/
public class ClientOneToOneServerFrame extends JFrame
private JTextArea ta_info;
private ServerSocket server; // 声明ServerSocket对象
private Socket socket; // 声明Socket对象socket
private Hashtable<String, Socket> map = new Hashtable<String, Socket>();// 用于存储连接到服务器的用户和客户端套接字对象
public void createSocket()
try
server = new ServerSocket(9527);
while (true)
ta_info.append("等待新客户连接......\\n");
socket = server.accept();// 创建套接字对象
ta_info.append("客户端连接成功。" + socket + "\\n");
new ServerThread(socket).start();// 创建并启动线程对象
catch (IOException e)
e.printStackTrace();
class ServerThread extends Thread
Socket socket;
public ServerThread(Socket socket)
this.socket = socket;
public void run()
try
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));// 创建输入流对象
while (true)
String info = in.readLine();// 读取信息
String key = "";
if (info.startsWith("用户:")) // 添加登录用户到客户端列表
key = info.substring(3, info.length());// 获得用户名并作为键使用
map.put(key, socket);// 添加键值对
Set<String> set = map.keySet();// 获得集合中所有键的Set视图
Iterator<String> keyIt = set.iterator();// 获得所有键的迭代器
while (keyIt.hasNext())
String receiveKey = keyIt.next();// 获得表示接收信息的键
Socket s = map.get(receiveKey);// 获得与该键对应的套接字对象
PrintWriter out = new PrintWriter(s
.getOutputStream(), true);// 创建输出流对象
Iterator<String> keyIt1 = set.iterator();// 获得所有键的迭代器
while (keyIt1.hasNext())
String receiveKey1 = keyIt1.next();// 获得键,用于向客户端添加用户列表
out.println(receiveKey1);// 发送信息
out.flush();// 刷新输出缓冲区
else // 转发接收的消息
key = info.substring(info.indexOf(":发送给:") + 5, info
.indexOf(":的信息是:"));// 获得接收方的key值,即接收方的用户名
String sendUser = info.substring(0, info
.indexOf(":发送给:"));// 获得发送方的key值,即发送方的用户名
Set<String> set = map.keySet();// 获得集合中所有键的Set视图
Iterator<String> keyIt = set.iterator();// 获得所有键的迭代器
while (keyIt.hasNext())
String receiveKey = keyIt.next();// 获得表示接收信息的键
if (key.equals(receiveKey)
&& !sendUser.equals(receiveKey)) // 如果是发送方,但不是用户本身
Socket s = map.get(receiveKey);// 获得与该键对应的套接字对象
PrintWriter out = new PrintWriter(s
.getOutputStream(), true);// 创建输出流对象
out.println("MSG:"+info);// 发送信息
out.flush();// 刷新输出缓冲区
catch (IOException e)
ta_info.append(socket + "已经退出。\\n");
/**
* Launch the application
*
* @param args
*/
public static void main(String args[])
ClientOneToOneServerFrame frame = new ClientOneToOneServerFrame();
frame.setVisible(true);
frame.createSocket();
/**
* Create the frame
*/
public ClientOneToOneServerFrame()
super();
setTitle("客户端一对一通信——服务器端程序");
setBounds(100, 100, 385, 266);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JScrollPane scrollPane = new JScrollPane();
getContentPane().add(scrollPane, BorderLayout.CENTER);
ta_info = new JTextArea();
scrollPane.setViewportView(ta_info);
ClientOneToOneClientFrame
package com.xiaoxuzhu;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.*;
/**
* Description:
*
* @author xiaoxuzhu
* @version 1.0
*
* <pre>
* 修改记录:
* 修改后版本 修改人 修改日期 修改内容
* 2022/6/5.1 xiaoxuzhu 2022/6/5 Create
* </pre>
* @date 2022/6/5
*/
public class ClientOneToOneClientFrame extends JFrame
private JTextField tf_newUser;
private JList user_list;
private JTextArea ta_info;
private JTextField tf_send;
PrintWriter out;// 声明输出流对象
private boolean loginFlag = false;// 为true时表示已经登录,为false时表示未登录
private Socket socket;
/**
* Launch the application
*
* @param args
*/
public static void main(String args[])
EventQueue.invokeLater(new Runnable()
public void run()
try
ClientOneToOneClientFrame frame = new ClientOneToOneClientFrame();
frame.setVisible(true);
frame.createClientSocket();// 调用方法创建套接字对象
catch (Exception e)
e.printStackTrace();
);
public void createClientSocket()
try
socket = new Socket("127.0.0.1", 9527);// 创建套接字对象
out = new PrintWriter(socket.getOutputStream(), true);// 创建输出流对象
SwingWorker<Void,Void> worker=new SwingWorker<Void, Void>()
@Override
protected Void doInBackground() throws Exception
try
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));// 创建输入流对象
DefaultComboBoxModel model = (DefaultComboBoxModel) user_list
.getModel();// 获得列表框的模型
while (true)
String info = in.readLine().trim();// 读取信息
if (!info.startsWith("MSG:"))
boolean itemFlag = false;// 标记是否为列表框添加列表项,为true不添加,为false添加
for (int i = 0; i < model.getSize(); i++)
if (info.equals((String) model.getElementAt(i)))
itemFlag = true;
if (!itemFlag)
model.addElement(info);// 添加列表项
else
itemFlag = false;
else
ta_info.append(info + "\\n");// 在文本域中显示信息
if (info.equals("88"))
break;// 结束线程
catch (IOException e)
e.printStackTrace();
return null;
;
worker.execute();
catch (UnknownHostException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
private void send()
if (!loginFlag)
JOptionPane.showMessageDialog(null, "请先登录。");
return;
String sendUserName = tf_newUser.getText().trim();
String info = tf_send.getText();// 获得输入的信息
if (info.equals(""))
return;// 如果没输入信息则返回,即不发送
String receiveUserName = (String) user_list.getSelectedValue();// 获得接收信息的用户
String msg = sendUserName + ":发送给:" + receiveUserName + ":的信息是: "
+ info;// 定义发送的信息
if (info.equals("88"))
System.exit(0);// 如果没输入信息是88,则退出
out.println(msg);// 发送信息
out.flush();// 刷新输出缓冲区
tf_send.setText(null);// 清空文本框
/**
* Create the frame
*/
public ClientOneToOneClientFrame()
super();
setTitle("客户端一对一通信——客户端程序");
setBounds(100, 100, 385, 288);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel();
getContentPane().add(panel, BorderLayout.SOUTH);
final JLabel label = new JLabel();
label.setText("输入聊天内容:");
panel.add(label);
tf_send = new JTextField();
tf_send.addActionListener(new ActionListener()
public void actionPerformed(final ActionEvent e)
send();// 调用方法发送信息
);
tf_send.setPreferredSize(new Dimension(180, 25));
panel.add(tf_send);
final JButton button = new 第94题JAVA高级技术-网络编程13(简易聊天室8:使用Socket传递图片)
第95题JAVA高级技术-网络编程14(简易聊天室9:使用Socket传递音频)
第99题JAVA高级技术-网络编程18(简易聊天室13:聊天室服务端)
第99题JAVA高级技术-网络编程18(简易聊天室13:聊天室服务端)