热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Java多线程实现聊天客户端和服务器

这篇文章主要为大家详细介绍了Java多线程聊天客户端和服务器实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了java聊天室代码,供大家参考,具体内容如下

主要涉及知识

·Java中GUI程序的编写,包括事件监听机制。
·Java的网络通信编程,ServerSocket,Socket类的使用。
·Java中多线程的编程,Thread类,Runnable接口的使用。

源代码

客户端

package project1; 
 
import java.awt.*; 
import java.awt.event.*; 
import java.io.*; 
import java.net.*; 
 
import javax.swing.*; 
 
public class Client { 
 private JFrame clientFrame; 
 private JLabel IPLabel; 
 private JLabel PortLabel; 
 private JLabel sayLabel; 
 private JLabel nicknameLabel; 
 private JTextField IPText; 
 private JTextField PortText; 
 private JTextField nicknameText; 
 private JTextField sayText; 
 private JButton connectButton; 
 private JButton nicknameButton; 
 private JButton sayButton; 
 private JPanel jPanelNorth; 
 private JPanel jPanelSouth0; 
 private JPanel jPanelSouth1; 
 private JPanel jPanelSouth2; 
 private JTextArea clientTextArea; 
 private JScrollPane scroller; 
 private BufferedReader reader; 
 private PrintWriter writer; 
 private String nickname; 
 
 public static void main(String args[]) { 
  Client aClient = new Client(); 
  aClient.startUp(); 
 } 
 
 // 初始化组件 
 public Client() { 
  nickname = "客户端"; 
 
  clientFrame = new JFrame(); 
  jPanelNorth = new JPanel(); 
  IPLabel = new JLabel("服务器IP", JLabel.LEFT); 
  IPText = new JTextField(10); 
  PortLabel = new JLabel("服务器端口", JLabel.LEFT); 
  PortText = new JTextField(10); 
  cOnnectButton= new JButton("连接"); 
  clientTextArea = new JTextArea(); 
  scroller = new JScrollPane(clientTextArea); 
  jPanelSouth0 = new JPanel(); 
  jPanelSouth1 = new JPanel(); 
  jPanelSouth2 = new JPanel(); 
  nicknameLabel = new JLabel("昵称", JLabel.LEFT); 
  nicknameText = new JTextField(nickname, 30); 
  nicknameButton = new JButton("确认"); 
  sayLabel = new JLabel("消息", JLabel.LEFT); 
  sayText = new JTextField(30); 
  sayButton = new JButton("确认"); 
 } 
 
 // 构建GUI 
 private void buildGUI() { 
  // 窗口的设置 
  clientFrame.setTitle("客户端"); 
  clientFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
  clientFrame.setSize(550, 550); 
 
  // 北区的组件 
  jPanelNorth.add(IPLabel); 
  jPanelNorth.add(IPText); 
  jPanelNorth.add(PortLabel); 
  jPanelNorth.add(PortText); 
  jPanelNorth.add(connectButton); 
  clientFrame.getContentPane().add(BorderLayout.NORTH, jPanelNorth); 
 
  // 中间的组件 
  clientTextArea.setFocusable(false); 
  scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 
  scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 
  clientFrame.getContentPane().add(BorderLayout.CENTER, scroller); 
 
  // 南区的组件 
  jPanelSouth1.add(nicknameLabel); 
  jPanelSouth1.add(nicknameText); 
  jPanelSouth1.add(nicknameButton); 
  jPanelSouth2.add(sayLabel); 
  jPanelSouth2.add(sayText); 
  jPanelSouth2.add(sayButton); 
  jPanelSouth0.setLayout(new BoxLayout(jPanelSouth0, BoxLayout.Y_AXIS)); 
  jPanelSouth0.add(jPanelSouth1); 
  jPanelSouth0.add(jPanelSouth2); 
  clientFrame.getContentPane().add(BorderLayout.SOUTH, jPanelSouth0); 
 
  // 设置窗口可见 
  clientFrame.setVisible(true); 
 } 
 
 // 客户端运行 
 public void startUp() { 
  buildGUI(); 
 
  // 接收服务器消息的线程 
  Runnable incomingReader = new Runnable() { 
   @Override 
   public void run() { 
    String message; 
    try { 
     while ((message = reader.readLine()) != null) { 
      clientTextArea.append(message + "\n"); 
     } 
    } catch (Exception ex) { 
     ex.printStackTrace(); 
    } 
   } 
  }; 
 
  // 监听Connect按钮,实现服务器的连接 
  connectButton.addActionListener(new ActionListener() { 
   @Override 
   public void actionPerformed(ActionEvent e) { 
    String aServerIP = IPText.getText(); 
    String aServerPort = PortText.getText(); 
 
    if (aServerIP.equals("") || aServerPort.equals("")) { 
     JOptionPane.showMessageDialog(clientFrame, "请输入 完整的 IP和端口!"); 
    } else { 
     try { 
      @SuppressWarnings("resource") 
      Socket clientSocket = new Socket(aServerIP, Integer.parseInt(aServerPort)); 
      InputStreamReader streamReader = new InputStreamReader(clientSocket.getInputStream()); 
      reader = new BufferedReader(streamReader); 
      writer = new PrintWriter(clientSocket.getOutputStream()); 
 
      clientTextArea.append("服务器已连接...\n"); 
 
      Thread readerThread = new Thread(incomingReader); 
      readerThread.start(); 
     } catch (Exception ex) { 
      JOptionPane.showMessageDialog(clientFrame, "连接不上服务器!\n请确认 IP 和 端口 输入正确。"); 
     } 
    } 
   } 
  }); 
 
  // 监听nickname,设置昵称 
  ActionListener nicknameListener = new ActionListener() { 
   @Override 
   public void actionPerformed(ActionEvent e) { 
    String aText = nicknameText.getText(); 
    if (!aText.equals("")) { 
     nickname = aText; 
    } 
   } 
  }; 
  nicknameButton.addActionListener(nicknameListener); 
  nicknameText.addActionListener(nicknameListener); 
  nicknameText.addFocusListener(new FocusListener() { 
   @Override 
   public void focusGained(FocusEvent e) { 
   } 
 
   @Override 
   public void focusLost(FocusEvent e) { 
    String aText = nicknameText.getText(); 
    if (!aText.equals("")) { 
     nickname = aText; 
    } 
   } 
  }); 
 
  // 发送消息到服务器 
  ActionListener SayListener = new ActionListener() { 
   @Override 
   public void actionPerformed(ActionEvent e) { 
    String aText = sayText.getText(); 
    if (aText.equals("")) { 
     JOptionPane.showMessageDialog(clientFrame, "内容不能为空!"); 
    } else { 
     try { 
      writer.println(nickname + ":" + aText); 
      writer.flush(); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
     sayText.setText(""); 
    } 
   } 
  }; 
  sayButton.addActionListener(SayListener); 
  sayText.addActionListener(SayListener); 
 
 } 
 
} 

服务器

package project1; 
 
import java.awt.*; 
import java.awt.event.*; 
import java.io.*; 
import java.net.*; 
import java.util.ArrayList; 
import java.util.Iterator; 
import javax.swing.*; 
 
public class Server { 
 private JFrame serverFrame; 
 private JLabel portLabel; 
 private JLabel sayLabel; 
 private JLabel nicknameLabel; 
 private JTextField portText; 
 private JTextField sayText; 
 private JTextField nicknameText; 
 private JButton startButton; 
 private JButton sayButton; 
 private JButton nicknameButton; 
 private JPanel jPanelNorth; 
 private JPanel jPanelSouth0; 
 private JPanel jPanelSouth1; 
 private JPanel jPanelSouth2; 
 private JScrollPane scroller; 
 private JTextArea serverTextArea; 
 private ArrayList clientOutputStreams; 
 private String nickname; 
 
 public static void main(String[] args) { 
  Server aServer = new Server(); 
  aServer.startUp(); 
 } 
 
 // 初始化组件 
 public Server() { 
  nickname = "服务器"; 
 
  serverFrame = new JFrame(); 
  jPanelNorth = new JPanel(); 
  portLabel = new JLabel("端口", JLabel.LEFT); 
  portText = new JTextField(30); 
  startButton = new JButton("开始"); 
  serverTextArea = new JTextArea(); 
  scroller = new JScrollPane(serverTextArea); 
  nicknameLabel = new JLabel("昵称", JLabel.LEFT); 
  nicknameText = new JTextField(nickname, 30); 
  nicknameButton = new JButton("确认"); 
  jPanelSouth0 = new JPanel(); 
  jPanelSouth1 = new JPanel(); 
  jPanelSouth2 = new JPanel(); 
  sayLabel = new JLabel("消息", JLabel.LEFT); 
  sayText = new JTextField(30); 
  sayButton = new JButton("确认"); 
 } 
 
 // 构建GUI 
 private void buildGUI() { 
  // 窗口的设置 
  serverFrame.setTitle("服务器"); 
  serverFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
  serverFrame.setSize(550, 550); 
 
  // 北区的组件 
  jPanelNorth.add(portLabel); 
  jPanelNorth.add(portText); 
  jPanelNorth.add(startButton); 
  serverFrame.getContentPane().add(BorderLayout.NORTH, jPanelNorth); 
 
  // 中间的组件 
  serverTextArea.setFocusable(false); 
  scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 
  scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 
  serverFrame.getContentPane().add(BorderLayout.CENTER, scroller); 
 
  // 南区的组件 
  jPanelSouth1.add(nicknameLabel); 
  jPanelSouth1.add(nicknameText); 
  jPanelSouth1.add(nicknameButton); 
  jPanelSouth2.add(sayLabel); 
  jPanelSouth2.add(sayText); 
  jPanelSouth2.add(sayButton); 
  jPanelSouth0.setLayout(new BoxLayout(jPanelSouth0, BoxLayout.Y_AXIS)); 
  jPanelSouth0.add(jPanelSouth1); 
  jPanelSouth0.add(jPanelSouth2); 
  serverFrame.getContentPane().add(BorderLayout.SOUTH, jPanelSouth0); 
 
  // 设置窗口可见 
  serverFrame.setVisible(true); 
 } 
 
 // 服务器运行 
 public void startUp() { 
  buildGUI(); 
 
  // 监听Start按钮,建立端口 
  ActionListener startListener = new ActionListener() { 
   @Override 
   public void actionPerformed(ActionEvent e) { 
    clientOutputStreams = new ArrayList(); 
    String aPort = portText.getText(); 
 
    if (aPort.equals("")) { 
     JOptionPane.showMessageDialog(serverFrame, "请输入正确的端口号!"); 
    } else { 
     try { 
      // 等待客户端连接的线程 
      Runnable serverRunnable = new Runnable() { 
       @Override 
       public void run() { 
        ServerSocket serverSocket; 
        try { 
         serverSocket = new ServerSocket(Integer.parseInt(aPort)); 
         serverTextArea.append("正在等待客户端连接...\n"); 
         while (true) { 
          Socket clientSocket = serverSocket.accept(); 
          serverTextArea.append("客户端已连接...\n"); 
 
          PrintWriter writer = new PrintWriter(clientSocket.getOutputStream()); 
          clientOutputStreams.add(writer); 
 
          Thread t = new Thread(new ClientHandler(clientSocket)); 
          t.start(); 
         } 
        } catch (NumberFormatException | IOException e) { 
         e.printStackTrace(); 
        } 
       } 
      }; 
      Thread serverThread = new Thread(serverRunnable); 
      serverThread.start(); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
    } 
   } 
  }; 
  startButton.addActionListener(startListener); 
  portText.addActionListener(startListener); 
 
  // 监听nickname,设置昵称 
  ActionListener nicknameListener = new ActionListener() { 
   @Override 
   public void actionPerformed(ActionEvent e) { 
    String aText = nicknameText.getText(); 
    if (!aText.equals("")) { 
     nickname = aText; 
    } 
   } 
  }; 
  nicknameButton.addActionListener(nicknameListener); 
  nicknameText.addActionListener(nicknameListener); 
  nicknameText.addFocusListener(new FocusListener() { 
   @Override 
   public void focusGained(FocusEvent e) { 
   } 
 
   @Override 
   public void focusLost(FocusEvent e) { 
    String aText = nicknameText.getText(); 
    if (!aText.equals("")) { 
     nickname = aText; 
    } 
   } 
  }); 
 
  // 监听Say按钮,发送消息 
  ActionListener SayListener = new ActionListener() { 
   @Override 
   public void actionPerformed(ActionEvent e) { 
    String aText = sayText.getText(); 
    if (!aText.equals("")) { 
     aText = nickname + ":" + aText; 
     sendToEveryClient(aText); 
     serverTextArea.append(aText + "\n"); 
     sayText.setText(""); 
    } else { 
     JOptionPane.showMessageDialog(serverFrame, "内容不能为空!"); 
    } 
   } 
  }; 
  sayButton.addActionListener(SayListener); 
  sayText.addActionListener(SayListener); 
 } 
 
 // 多客户端的线程 
 public class ClientHandler implements Runnable { 
  BufferedReader bReader; 
  Socket aSocket; 
 
  public ClientHandler(Socket clientSocket) { 
   try { 
    aSocket = clientSocket; 
    InputStreamReader isReader = new InputStreamReader(aSocket.getInputStream()); 
    bReader = new BufferedReader(isReader); 
   } catch (Exception ex) { 
    ex.printStackTrace(); 
   } 
  } 
 
  @Override 
  public void run() { 
   String message; 
   try { 
    while ((message = bReader.readLine()) != null) { 
     sendToEveryClient(message); 
     serverTextArea.append(message + "\n"); 
    } 
   } catch (Exception ex) { 
    ex.printStackTrace(); 
   } 
  } 
 } 
 
 // 发送消息给所有客户端的方法 
 private void sendToEveryClient(String message) { 
  Iterator it = clientOutputStreams.iterator(); 
  while (it.hasNext()) { 
   try { 
    PrintWriter writer = (PrintWriter) it.next(); 
    writer.println(message); 
    writer.flush(); 
   } catch (Exception ex) { 
    ex.printStackTrace(); 
   } 
  } 
 } 
 
} 

GUI运行截图:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 本文介绍了如何找到并终止在8080端口上运行的进程的方法,通过使用终端命令lsof -i :8080可以获取在该端口上运行的所有进程的输出,并使用kill命令终止指定进程的运行。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 如何基于ggplot2构建相关系数矩阵热图以及一个友情故事
    本文介绍了如何在rstudio中安装ggplot2,并使用ggplot2构建相关系数矩阵热图。同时,通过一个友情故事,讲述了真爱难觅的故事背后的数据量化和皮尔逊相关系数的概念。故事中的小伙伴们在本科时参加各种考试,其中有些沉迷网络游戏,有些热爱体育,通过他们的故事,展示了不同兴趣和特长对学习和成绩的影响。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
author-avatar
9527
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有