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

使用Java网络编程,窗口,线程,IO,内部类等实现多人在线聊天1.0

1.整体思路

思路图

5b3c97a5649f45698a019a67b5c66527.png

整体思路如上: 涉及知识点:线程+网络编程+集合+IO等

 

TCP 协议

d1e074db85854c009a0f3ddcbb83c3cf.png

 2.代码实现过程

服务端

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;public class Server extends JFrame {//继承窗口来实现窗口功能/*设置接受客户端的集合,把接入服务器的客户端存入集合,方便后续的消息转发*/ArrayList<Socket> socketsClients = new ArrayList<>();/*由于下面线程需要调用窗口的一些东西,所以需要全局变量*/JTextArea jTextArea;JTextArea jTextSend = new JTextArea(30,20);//只能设置几列JButton jButtonSend = new JButton("发送") ;public Server() {//创建服务器窗口 一些列属性//主面板JPanel priorPanel = new JPanel(new BorderLayout());//显示消息this.setDefaultCloseOperation(EXIT_ON_CLOSE);//关闭窗口结束程序this.setTitle("来自客户端的消息");this.setSize(500, 500);jTextArea = new JTextArea();//显示客户端的信息jTextArea.setEditable(false);//不可以修改 面板信息JScrollPane clientInformation = new JScrollPane(jTextArea);priorPanel.add(clientInformation,BorderLayout.CENTER);//写一个发布公告的窗口JPanel sendPanel = new JPanel();//默认流式布局JScrollPane jScrollPane = new JScrollPane(jTextSend);jScrollPane.setPreferredSize(new Dimension(400,50));sendPanel.add(jScrollPane);sendPanel.add(jButtonSend);priorPanel.add(sendPanel,BorderLayout.SOUTH);this.add(priorPanel);//创建监听发送键 jButtonSend.addActionListener(new ActionListener() {/*用来对每个客户端发送公告*/@Overridepublic void actionPerformed(ActionEvent e) {String announcement = "来自服务器的公告:"+jTextSend.getText()+"\n";//把公告发布到聊天界面jTextArea.append(announcement);/*使用for循环来遍历每个客户端的对象*/for(Socket soc:socketsClients){DataOutputStream dataOutputStream = null;try {dataOutputStream = new DataOutputStream(soc.getOutputStream());dataOutputStream.writeUTF(announcement+"\n");} catch (IOException ioException) {ioException.printStackTrace();}}jTextSend.setText(null);}});this.setVisible(true);
//===================================================================================
//以上为窗口的创建,下面为功能的实现try {//创建服务器对象 设置端口ServerSocket serverSocket = new ServerSocket(9998);//使用无限循环来不停接受客户端的连接while(true){Socket socketClient = serverSocket.accept();//接收到一个就向集合加入一个客户端socketsClients.add(socketClient);//就收一个连接就在后台提示一遍System.out.println("有"+socketsClients.size()+"个邓钦文连接到服务器!");//然后启动该客户端的线程  线程的实现则需要我们使用内部类new SocketThread(socketClient).start();}//处理客户端输入的东西} catch (IOException e) {e.printStackTrace();System.out.println("服务器启动失败!");}}//创建监听//创建内部类 线程class SocketThread extends Thread{DataInputStream dataInputStream;Socket socket;/*构建方法 传入当前客户的连接*/public SocketThread(Socket socket) throws IOException {/*接受客户端的输入流*/dataInputStream = new DataInputStream(socket.getInputStream());this.socket = socket;}/*重写run方法 来实现对客户端的操作方法*/@Overridepublic void run() {while(true){try {String msg = dataInputStream.readUTF();/*读取客户端的信息 并打印到自己的窗口上*/jTextArea.append(msg+"\n");//给每一个客户端发送信息  实现群聊的效果for(Socket soc:socketsClients){DataOutputStream dataOutputStream = new DataOutputStream(soc.getOutputStream());dataOutputStream.writeUTF(msg+"\n");}} catch (IOException e) {e.printStackTrace();System.out.println("读取失败!");socketsClients.remove(socket);return;}}}}}

客户端

登录界面

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.Socket;public class EnterFrame extends JFrame {public EnterFrame() throws HeadlessException {this.setSize(600,500);this.setTitle("欢迎登录");this.setResizable(true);this.setDefaultCloseOperation(EXIT_ON_CLOSE);//关闭窗口结束程序this.setLocationRelativeTo(this);JPanel jPanelLast = new JPanel(new GridLayout(4,1));//头顶部分JPanel jPanelTop = new JPanel();JLabel jLabel = new JLabel("欢迎登录");jLabel.setFont(new Font("宋体",Font.BOLD,30));//中间部分JPanel jPanelMiddle = new JPanel(new GridLayout(2,1,0,0));JPanel jPanelAccount = new JPanel(new FlowLayout());//账号密码输入端JLabel jLabelAccount = new JLabel("账号");JTextField jTextFieldAccount = new JTextField(15);jPanelAccount.add(jLabelAccount);jPanelAccount.add(jTextFieldAccount);JPanel jPanelPassword = new JPanel(new FlowLayout());JLabel jLabelPassword = new JLabel("密码");JPasswordField jTextFieldPassword = new JPasswordField(15);jPanelPassword.add(jLabelPassword);jPanelPassword.add(jTextFieldPassword);//底部  登录按钮端JPanel jPanelFoot = new JPanel();JPanel jPanelButton = new JPanel(new FlowLayout());JButton enterButton = new JButton("登录");JButton signButton = new JButton("注册");jPanelButton.add(enterButton);jPanelButton.add(signButton);jPanelTop.add(jLabel);jPanelMiddle.add(jPanelAccount);jPanelMiddle.add(jPanelPassword);jPanelFoot.add(jPanelButton);jPanelLast.add(jPanelTop);jPanelLast.add(jPanelMiddle);jPanelLast.add(jPanelFoot);this.add(jPanelLast);this.setVisible(true);
//================================================================================
//以上为登录界面窗口的设计  可以自己设计//设计监听事件  来判断用户的读取enterButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {
//1.判断不能为空if(jTextFieldAccount.getText().length()<=0||jTextFieldPassword.getText().length()<=0) {JOptionPane.showMessageDialog(null, "输入的账号或密码为空!");return;}
//2.输入只能为数字与字母if((jTextFieldAccount.getText().matches("[a-zA-Z0-9]*")&&jTextFieldPassword.getText().matches("[a-zA-Z0-9]*"))==false){JOptionPane.showMessageDialog(null,"输入的账号或密码只能为字母和数字");return;}//如果都满足了登录成功 创建 客户端对象 输入服务器地址 与端口  关闭登录界面try {Socket socket = new Socket("127.0.0.1", 9998);new ChatFrame(jTextFieldAccount.getText(),socket);dispose();//关闭了登录窗口} catch (IOException ioException) {ioException.printStackTrace();JOptionPane.showMessageDialog(null,"无法连接服务器");}}});}}

聊天界面

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;public class ChatFrame extends JFrame {JTextArea jTextArea;public ChatFrame(String account , Socket socket) throws HeadlessException {this.setSize(700, 600);this.setTitle("欢迎来到"+account+"聊天室");this.setResizable(true);this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);JPanel jPanelEnd = new JPanel( new BorderLayout());//最终面板jTextArea = new JTextArea();jTextArea.setEditable(false);JScrollPane jScrollPane1 = new JScrollPane(jTextArea);jPanelEnd.add(jScrollPane1,BorderLayout.CENTER);JPanel jPanelInput = new JPanel();JTextArea jTextArea2 = new JTextArea(5,40);//带滑动的窗口JScrollPane jScrollPane2 = new JScrollPane(jTextArea2);//不能通过add加入,只能通过构造方法加入,这样不会出现不显示的问题jPanelInput.add(jScrollPane2);JButton jButtonSend = new JButton("发送");jPanelInput.add(jButtonSend);jPanelEnd.add(jPanelInput,BorderLayout.SOUTH);this.add(jPanelEnd);try {new ClientThread(socket).start();} catch (IOException e) {e.printStackTrace();JOptionPane.showMessageDialog(null,"发送错误");}
//关闭窗口,显示登录窗口this.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {System.out.println("你确定要关闭我妈?");int res = JOptionPane.showConfirmDialog(null,"你确定要关闭我吗","操作提示",JOptionPane.OK_CANCEL_OPTION);if(res==0){//点击确定new EnterFrame();dispose();//关闭当前对象}}});//监听发送事件try {DataOutputStream socketOutput = new DataOutputStream(socket.getOutputStream());String message = socketOutput.toString();jButtonSend.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if(message.length()<=0){JOptionPane.showMessageDialog(null,"输入消息不能为空!");return;}String msg = account+" "+ new SimpleDateFormat("yyyy-MM HH:mm:ss").format(new Date()) +"\n"+jTextArea2.getText();try {socketOutput.writeUTF(msg);System.out.println(msg);jTextArea2.setText("");} catch (IOException ioException) {ioException.printStackTrace();JOptionPane.showMessageDialog(null,"发生错误");}}});} catch (IOException e) {e.printStackTrace();}this.setVisible(true);
//=======================================================================================
//窗口的创建以及窗口功能的实现}//创建内部列 创建客户端的线程,解决多个聊天窗口同时实现class ClientThread extends  Thread{DataInputStream inputStream;Socket socket;/*构造方法*/public ClientThread(Socket socket) throws IOException {inputStream = new DataInputStream(socket.getInputStream());this.socket = socket;}@Overridepublic void run() {try {while(true){/*把接受的到信息添加到窗口中*/String msg = inputStream.readUTF();jTextArea.append(msg+"\n");}} catch (IOException e) {e.printStackTrace();return;}}}
}

启动程序

public class RunOfServer {public static void main(String[] args) {new Server();}
}
public class RunOfClient {public static void main(String[] args) {new EnterFrame();}
}

3.实现结果

1.启动服务器

16182041264b49778e2ebac0c2d25cf0.png

2.尝试启动 3个客户端  并登录

6c3652a6f8204a21a45bfd4673edef3c.png 5d985973b0ab475eaa8ff03c7b25195d.png

 3.测试消息发送接收以及公告发送功能.

803003105bc245249faa05dd85651dfb.png

4.总结

本次聊天室1.0的简单实现使用了 Java 的网络编程 IO 线程 异常的抛出 集合 内部类 GUI等 

希望指出错误并提供改进意见 

 

http://www.lryc.cn/news/254480.html

相关文章:

  • 相关教程test
  • mysql知识分享(包含安装卸载)(一)
  • Google Guava 反射工具使用详解
  • MySql MVCC 详解
  • 工业机器视觉megauging(向光有光)使用说明书(三,轻量级的visionpro)
  • Linux 环境下,jdbc连接mysql问题
  • Python读写txt文件数据
  • Linux虚假唤醒
  • 倒计时模块复习
  • k8s(三): 基本概念-ReplicaSet与Deployment
  • Linux 的介绍和云服务器上web 程序部署
  • Oauth2.0 学习
  • Elasticsearch:什么是向量数据库?
  • rename--统一的PRF
  • 010-editor破解(1)
  • Ubuntur编译ROS报错:error PCL requires C++14 or above
  • 17.认识下Docker之docker的核心原理(2)
  • 【EasyExcel实践】万能导出,一个接口导出多张表以及任意字段(可指定字段顺序)
  • 代码随想录算法训练营第四十二天 _ 动态规划_01背包问题、416.分割等和子集。
  • 市场上好用的aspera替代方案,你知道哪些
  • Stm32_串口的帧(不定长)数据接收
  • L0、Linux常用命令
  • Golang实践录:读取toml配置
  • 超大规模集成电路设计----基于阵列的可编程逻辑(七)
  • 深入探索FastAPI单元测试:使用TestClient轻松测试你的API
  • 基于ssm小型企业办公自动化系统论文
  • CasADi - 最优控制开源 Python/MATLAB 库
  • Java中使用String字符串的注意事项
  • 离线数仓构建案例一
  • nginx优雅如何优雅的接管【跨域配置】