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<PrintWriter> 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<PrintWriter>();
    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<PrintWriter> it = clientOutputStreams.iterator();
  while (it.hasNext()) {
   try {
    PrintWriter writer = (PrintWriter) it.next();
    writer.println(message);
    writer.flush();
   } catch (Exception ex) {
    ex.printStackTrace();
   }
  }
 } 

}

GUI运行截图:

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

(0)

相关推荐

  • Java多线程--让主线程等待所有子线程执行完毕在执行

    朋友让我帮忙写个程序从文本文档中导入数据到oracle数据库中,技术上没有什么难度,文档的格式都是固定的只要对应数据库中的字段解析就行了,关键在于性能. 数据量很大百万条记录,因此考虑到要用多线程并发执行,在写的过程中又遇到问题,我想统计所有子进程执行完毕总共的耗时,在第一个子进程创建前记录当前时间用System.currentTimeMillis()在最后一个子进程结束后记录当前时间,两次一减得到的时间差即为总共的用时,代码如下 long tStart = System.currentTime

  • 简单谈谈RxJava和多线程并发

    前言 相信对于RxJava,大家应该都很熟悉,他最核心的两个字就是异步,诚然,它对异步的处理非常的出色,但是异步绝对不等于并发,更不等于线程安全,如果把这几个概念搞混了,错误的使用RxJava,是会来带非常多的问题的. RxJava与并发 首先让我们来看一段RxJava协议的原文: Observables must issue notifications to observers serially (not in parallel). They may issue these notificat

  • Java多线程之readwritelock读写分离的实现代码

    在多线程开发中,经常会出现一种情况,我们希望读写分离.就是对于读取这个动作来说,可以同时有多个线程同时去读取这个资源,但是对于写这个动作来说,只能同时有一个线程来操作,而且同时,当有一个写线程在操作这个资源的时候,其他的读线程是不能来操作这个资源的,这样就极大的发挥了多线程的特点,能很好的将多线程的能力发挥出来. 在Java中,ReadWriteLock这个接口就为我们实现了这个需求,通过他的实现类ReentrantReadWriteLock我们可以很简单的来实现刚才的效果,下面我们使用一个例子

  • java实现多线程之定时器任务

    在Java中Timer是java.util包中的一个工具类,提供了定时器的功能.我们可以创建一个Timer对象,然后调用其schedule方法在某个特定的时间去执行一个特定的任务.并且你可以让其以特定频率一直执行某个任务,这个任务是用TimerTask来描述的,我们只需要将要进行的操作写在TimerTask类的run方法中即可.先附上两个小例子一遍让读者了解什么是定时器.接着再分析其中的一些源码实现. 第一个小例子: package com.zkn.newlearn.thread; import

  • java多线程实现服务器端与多客户端之间的通信

    用java语言构建一个网络服务器,实现客户端和服务器之间通信,实现客户端拥有独立线程,互不干扰. 应用多线程来实现服务器与多线程之间的通信的基本步骤 服务器端创建ServerSocket,循环调用accept()等待客户端链接 客户端创建一个Socket并请求和服务器端链接 服务器端接受客户端请求,创建socekt与该客户端建立专线链接 建立链接的socket在一个单独的线程上对话 服务器继续等待新的链接 服务器端Server.java package test.concurrent.socke

  • Java多线程下载文件实例详解

    本文实例为大家分享了Java多线程下载文件的具体代码,供大家参考,具体内容如下 import java.io.File; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; public class MulThreadDownload { public static void main(String[] args)

  • JAVA多线程并发下的单例模式应用

    单例模式应该是设计模式中比较简单的一个,也是非常常见的,但是在多线程并发的环境下使用却是不那么简单了,今天给大家分享一个我在开发过程中遇到的单例模式的应用. 首先我们先来看一下单例模式的定义: 一个类有且仅有一个实例,并且自行实例化向整个系统提供. 单例模式的要素: 1.私有的静态的实例对象 2.私有的构造函数(保证在该类外部,无法通过new的方式来创建对象实例) 3.公有的.静态的.访问该实例对象的方法 单例模式分为懒汉形和饿汉式 懒汉式: 应用刚启动的时候,并不创建实例,当外部调用该类的实例

  • 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.*; impo

  • Java多线程局域网聊天室的实现

    局域网聊天室 在学习了一个学期的java以后,觉得java真是博大精深,彻底放弃了因为c++而轻视java的心态,搞了一个多线程的聊天室,熟悉了一下服务器和客户机的操作. 1.TCP 要实现局域网连接,就必须知道信息传输的原理. 在局域网里面传输的信息都是以包的形式,我使用的TCP包传输数据,TCP包里面封装了IP报文. 下面这句话就是通过一个静态IPV4协议的类得到一个服务器的IP地址. address = InetAddress.getByName("192.168.43.86")

  • Java多线程实现多人聊天室功能

    本文为大家分享了Java多线程实现多人聊天室功能的具体代码,供大家参考,具体内容如下 1.实验目的: 编写一个 Java 应用程序,实现图形界面多人聊天室(多线程实现),要求聊天室窗口标题是 "欢迎使用 XXX 聊天室应用",其中 XXX 是自己的班级姓名学号,如"软件 171 张三 1234". 2.实验代码: 服务端程序代码: ServerChar.java package works; import java.io.DataInputStream; impor

  • Java创建多线程局域网聊天室实例

    局域网聊天室 在学习了一个学期的java以后,觉得java真是博大精深,彻底放弃了因为c++而轻视java的心态,搞了一个多线程的聊天室,熟悉了一下服务器和客户机的操作. 1.TCP 要实现局域网连接,就必须知道信息传输的原理. 在局域网里面传输的信息都是以包的形式,我使用的TCP包传输数据,TCP包里面封装了IP报文. 下面这句话就是通过一个静态IPV4协议的类得到一个服务器的IP地址. address = InetAddress.getByName("192.168.43.86")

  • java模拟客户端向服务器上传文件

    本文实例为大家分享了java客户端向服务器上传文件的具体代码,供大家参考,具体内容如下 先来了解一下客户端与服务器Tcp通信的基本步骤: 服务器端先启动,然后启动客户端向服务器端发送数据. 服务器端收到客户端发送的数据,服务器端会响应应客户端,向客户端发送响应结果. 客户端读取服务器发送的数据 文件上传步骤: 客户端使用本地字节输入流,指定上传数据的数据源. 客户端使用网络字节输出流,把读取的本地文件上传到服务器. 服务器使用网络字节输入流,读取客户端上传的文件. 服务器使用本地字节输出流,把读

  • 基于Java的Socket多客户端Client-Server聊天程序的实现

    任务要求 编写一个简单的Socket多客户端聊天程序: 客户端程序,从控制台输入字符串,发送到服务器端,并将服务器返回的信息显示出来 服务器端程序,从客户机接收数据并打印,同时将从标准输入获取的信息发送给客户机 满足一个服务器可以服务多个客户 低配版本链接 实现代码 工具类 import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.Socket

  • java客户端登陆服务器用户名验证

    本文实例为大家分享了java客户端登陆服务器用户名验证的具体实现代码,供大家参考,具体内容如下 客户端通过键盘录入用户名,服务端对用户名进行验证.  如果用户名存在,服务端显示xxx已登录,客户端显示xxx,欢迎登陆. 如果用户名不存在,服务端显示xxx尝试登陆,客户端显示xxx,用户名不存在.  最多登陆三次,防止暴力登陆. import java.io.*; import java.net.*; /* *客户端 */ class client { public static void mai

  • Python实现基于多线程、多用户的FTP服务器与客户端功能完整实例

    本文实例讲述了Python实现基于多线程.多用户的FTP服务器与客户端功能.分享给大家供大家参考,具体如下: 项目介绍: 1. 用户加密认证 2. 允许同时多用户登录 3. 每个用户有自己的家目录 ,且只能访问自己的家目录 4. 对用户进行磁盘配额,每个用户的可用空间不同 5. 允许用户在ftp server上随意切换目录 6. 允许用户查看当前目录下文件 7. 允许上传和下载文件,保证文件一致性 8. 文件传输过程中显示进度条 实现的原理: 服务器端启用端口监听,并对每一连接启用一个线程,对用

  • java实现客户端向服务器发送文件

    本文实例为大家分享了java实现客户端向服务器发送文件的具体代码,供大家参考,具体内容如下 服务器源代码: import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.In

随机推荐