具体解释,描述代码的注释已经写的很清楚,这里就不多说了,看代码:

客户端类:

package socket;import java.io.BufferedReader;
import java.io.BufferedWriter;
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.util.Scanner;/*** 聊天室的客户端* * **/
public class Client {/** java.net.Socket 套接字 Socket封装了TCP协议的通讯细节,使用它就可以与服务端建立网络连接了,* 并且进行通讯。这里的通讯是以两条流的读写完成与服务端的数据交换的。*/private Socket socket;/*** 客户端构造方法,用于初始化客户端*/public Client() {try {/** 实例化Socket时需要传入两个参数: 1:服务端的地址信息(IP) 2:服务端打开的端口* * 我们可以通过IP找到网络上的服务端计算机,通过其打开的端口 可以连接到服务端应用程序。*/System.out.println("正在连接服务端...");socket = new Socket("localhost", 8088);System.out.println("已连接服务端!");} catch (Exception e) {e.printStackTrace();}}/*** 客户端开始工作的方法*/public void start() {try {//先启动服务端发消息的线程ServerHandler handler = new ServerHandler();Thread t = new Thread(handler);t.start();/** Socket提供的方法: OutputStream getOutputStream() 通过socket的该方法获取的输出流写出的字节会通过网络发送给* 远端计算机。*/OutputStream out = socket.getOutputStream();OutputStreamWriter osw = new OutputStreamWriter(out, "UTF-8");BufferedWriter bw = new BufferedWriter(osw);PrintWriter pw = new PrintWriter(bw, true);Scanner scanner = new Scanner(System.in);while (true) {String message = scanner.nextLine();pw.println(message);}} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {Client client = new Client();client.start();}private class ServerHandler implements Runnable {public void run() {try {InputStream in = socket.getInputStream();InputStreamReader isr = new InputStreamReader(in, "UTF-8");BufferedReader br = new BufferedReader(isr);String message;while((message=br.readLine())!=null) {System.out.println(message);}} catch (Exception e) {}}}
}

服务端类:

package socket;import java.io.BufferedReader;
import java.io.BufferedWriter;
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.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;/*** 聊天室的服务端* ***/
public class Server {/** 服务端使用的是ServerSocket 它有两个作用: 1:向系统申请端口。 2:接收请求该端口的所有客户端的连接。*/private ServerSocket server;/** 内部类可以访问外部类的属性,因此所有ClientHandler都可以访问到外部类* Server的属性,所以在这里定义一个数组保存所有ClientHandler对应客户端的* 输出流就可以做到共享了。以便每个客户端发消息过来对应的ClientHandler都可 以通过遍历这个数组拿到所有对应客户端的输出流广播消息。*/private List<PrintWriter> allOut = Collections.synchronizedList(new ArrayList<>());/*** 服务端构造方法,用来初始化服务端*/public Server() {try {/** 实例化的同时向系统申请服务端口,客户端Socket就是通过这个 端口与服务端建立连接的。如果该端口被系统其他程序占用了则 会抛出异常:* java.net.BindException:address already in use: JVM_bind* * 遇到该错误时解决办法: 1:首先检查是否自己开启过两次服务端,因为第一次启动已经占用了 该端口,如果再启动一遍时还申请该端口就会提示被占用了。* 2:如果没有启动过两次,那说明系统其他程序占用该端口了,需要更 换一个可用的。*/System.out.println("正在启动服务端...");server = new ServerSocket(8088);System.out.println("服务端启动完毕!");} catch (IOException e) {e.printStackTrace();}}/*** 服务端开始工作的方法*/public void start() {try {/** ServerSocket提供的方法: Socket accept() 该方法是一个阻塞方法,调用该方法后程序"卡住",此时开始等待* 客户端的连接,一旦客户端实例化Socket并连接服务端这边申请的 端口(8088)时,accept方法会立即返回一个Socket实例,此时等于* 和客户端建立了连接。服务端通过返回的这个Socket就可以与客户端 进行交互了。 多次调用accept方法可以接收多个客户端的连接。*/while (true) {System.out.println("等待客户端连接...");Socket socket = server.accept();System.out.println("一个客户端连接了!");// 启动一个线程处理该客户端交互ClientHandler handler = new ClientHandler(socket);Thread t = new Thread(handler);t.start();}} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {Server server = new Server();server.start();}/*** 该线程任务用来与指定客户端交互* * @author Xiloer**/private class ClientHandler implements Runnable {private Socket socket;private String host;// 记录客户端的IP地址信息public ClientHandler(Socket socket) {this.socket = socket;// 通过socket获取远端计算机地址信息(对于服务端这边而言远端就是客户端)host = socket.getInetAddress().getHostAddress();}public void run() {PrintWriter pw = null;try {/** Socket提供的方法: InputStream getInputStream(); 通过该方法获取的输入流读取的字节是远端计算机发送过来的字节*/InputStream in = socket.getInputStream();InputStreamReader isr = new InputStreamReader(in, "UTF-8");BufferedReader br = new BufferedReader(isr);OutputStream out = socket.getOutputStream();OutputStreamWriter osw = new OutputStreamWriter(out, "UTF-8");BufferedWriter bw = new BufferedWriter(osw);pw = new PrintWriter(bw, true);/** 将输出流存入共享数组allOut中*/// 1将allOut数组扩容// 2将输出流存入数组最后一个位置allOut.add(pw);System.out.println(host + "上线了,当前在线人数:" + allOut.size());String message = "";while ((message = br.readLine()) != null) {String info = host + "说:" + message;System.out.println(info);// 回复所有客户端//                      for (int i = 0; i < allOut.length; i++) {
//                          allOut[i].println(host + "说:" + message);
//                      }allOut.forEach((p) -> p.println(info));}} catch (Exception e) {} finally {// 处理客户端锻开连接操作// 将对应当前客户端输入流从数组allOut中删除allOut.remove(pw);}System.out.println(host + "下线了,当前在线人数:" + allOut.size());try {/** socket的close方法调用后会与远程计算机断开连接 此时通过socket获取输入流与输出流也被close*/socket.close();} catch (IOException e) {e.printStackTrace();}}}
}

运行测试:

先点击运行服务端类,有以下提示:

然后点击运行客户端:
然后客户端的控制窗口会显示:

在服务端的控制窗口显示:
如果再次运行客户端,服务端的窗口显示为:

(提示:控制窗口切换)

然后切换到一个客户端控制窗口在里面输入文字:

就会在服务端显示:

如果关闭一个客户端,服务端窗口就会显示:

Socket套接字,一个简单的聊天室案例!相关推荐

  1. Netty - 一个简单的聊天室小项目

     经过一段时间对Netty的学习,我们对Netty各版本以及像ProtocolBuffers等技术应用都有了不少相关的了解, 我们就用这段时间学到的只是做一个简单的聊天室的小项目来练习自己学到的技术. ...

  2. 用ServletContext做一个简单的聊天室

    这里主要是ServletContext的一个特性:ServletContext是一个公共的空间,可以被所有的客户访问.由此可见ServletContext比cookie和session的作用范围要大[ ...

  3. python开发一个简单的聊天室

    使用python的twisted框架编写一个简单的聊天室 下面是基本架构 基本架构图 -- coding:utf-8 -- from twisted.internet.protocol import ...

  4. Android Socket通信(五) -- 实现一个多人聊天室

    系列文章: Android Socket 系列更新计划 Android Socket通信(一) – 初识与相遇 Android Socket通信(二) --UDP,单播,广播和多播(组播) Andro ...

  5. 前端+node实现一个简单的聊天室功能

    简单的实现一个聊天室功能 目录 前言 一.了解一下WebSocket 我们有了http协议,为什么会出现ws呢? ws出现之前,我们是怎么实现双向通信的呢? 二.使用到的websocket库 三.聊天 ...

  6. 使用Unity制作一个简单的聊天室

    使用控制台作为一个服务器,在Unity中开发客户端,制作一个简易的聊天室,无论哪个客户端发送消息,其他的客户端都会实时的显示出来. 服务器代码 using System; using System.C ...

  7. 使用netty搭建一个简单的聊天室

    1.导入maven依赖 <dependency><groupId>io.netty</groupId><artifactId>netty-all< ...

  8. python 土拨鼠库_为了应对某人的需求,写了一个简单的聊天室内容

    Python聊天室 背景 这是一篇水文,同时也是更换markdown后的第一篇,主要是为了测试markdown的情况. 服务器程序 #!/usr/bin/env python # -*- coding ...

  9. Go 实现一个简单的聊天室

    创建客户端 先在main方法中创建一个sorcket服务端,这个服务端就像一个酒店 func main() {listen, err := net.Listen("tcp", &q ...

  10. c# socket套接字

    C#是微软随着VS.net新推出的一门语言.它作为一门新兴的语言,有着C++的强健,又有着VB等的RAD特性.而且,微软推出C#主要的目的是为了对抗Sun公司的Java.大家都知道Java语言的强大功 ...

最新文章

  1. 深度学习「CV」学习实践指南!
  2. python画函数曲线-Python 绘制你想要的数学函数图形
  3. 函数计算搭建小程序Web应用后端服务
  4. /etc目录下重要文件解释
  5. 计算机组成原理3(集中式总线判优控制、总线通信控制)
  6. 制作chrome插件
  7. leetcode记录-罗马数字转整数
  8. rpcbind.service启动失败
  9. 供应链三道防线(读书笔记)3(共4)
  10. 用cheatengine实现街头霸王的无限生命
  11. java 判断两个字符串相等
  12. 第七篇 indicators(2)指标的绘制
  13. java double long 取值_由一道题引起的思考? java中 long 和double都是64位。为什么double表示的范围大那么多呢?...
  14. bzoj 1646 bfs
  15. ChatGPT提示词手册:学会提问的艺术,助你高效使用ChatGPT!
  16. 高仿人人车 范围选择器
  17. 【干货】ArcGIS常用标注技巧
  18. XILINX FPGA数字信号处理——13、信号同步原理实现
  19. HDU 6112 今夕何夕 蔡勒公式
  20. Java性能优化方法

热门文章

  1. 中南大学计算机学院王瑞,中南大学优秀毕业生.xls
  2. “龙书”作者Jeffery Ullman:相信你自己,自由地思考
  3. JAva继承编写自行车例子,java – Freemarker中的继承/实例检查
  4. 类和对象11:描述符方法
  5. 哪个大学开python课_2017春Python语言程序设计(天津大学仁爱学院)
  6. php输出绝对值,PHP实现找出有序数组中绝对值最小的数算法分析
  7. 针对Sql Server中进行查询操作时提示“对象名无效”
  8. 有空必须要看的文章(没空也要看)
  9. php 判断某一天是周几,php如何判断一个日期是周几
  10. 如何设置自定义任务栏图标_如何在Windows中自定义和调整系统任务栏图标