一、多用户服务器
多用户服务器是指服务器能同时支持多个用户并发访问服务器所提供的服务资源,如聊天服务、文件传输等。
上一篇的TCPServer是单用户版本,每次只能和一个用户对话。我们可以尝试多用户连接,开启多个客户端,具体操作如下:

这样就允许同时并行执行多个客户端,测试发现,单用户版本的TCPServer.java程序能同时支持多个用户并发连接(TCP三次握手),但不能同时服务多用户对话,只有前一个用户退出后,后面的用户才能完成服务器连接。
多线程技术,线程调用的并行执行。

上一篇提到在java中有两种实现多线程的方法,一是使用Thread类,二是使用Runnable类并实现run()方法。下面将使用Runnable类对服务端相关操作功能进行封装,结合上一篇,就学到了两种多线程实现方法。

//使用Runnable类,作为匿名内部类class Handler implements Runnable {public void run() {//实现run方法}}

服务器面临很多客户的并发连接,这种情况的多线程方案一般是:
主线程只负责监听客户请求和接受连接请求,用一个线程专门负责和一个客户对话,即一个客户请求成功后,创建一个新线程来专门负责该客户。对于这种方案,可以用上一篇方式new Thread创建线程,但是频繁创建线程需要消耗大量系统资源。所以不采用这种方法。
对于服务器,一般使用线程池来管理和复用线程。线程池内部维护了若干个线程,没有任务的时候,这些线程都处于等待状态。如果有新任务,就分配一个空闲线程执行。如果所有线程都处于忙碌状态,新任务要么放入队列等待,要么增加一个新线程进行处理。
显然,我们采用第2种线程池的方法。 常见创建方法如下:

ExecutorService executorService = Executors.newFixedThreadPool(n);//指定线程数量ExecutorService executorService = Executors.newCachedThreadPool();//动态线程池

接下来就是选择线程池的类型了。 使用第一个固定线程数的线程池,显然不够灵活,第二种方式的线程池会根据任务数量动态调整线程池的大小,作为小并发使用问题不大,但其在实际生产环境使用并不合适,如果并发量过大,常常会引发超出内存错误(OutOfMemoryError),根据我们的应用场景,可以用这个动态调整线程池。二、使用线程池实现服务端多线程1、单线程版本
首先,与之前的单线程通信对比一下,下面代码只能实现单用户与服务端通信,如果多用户与服务器通信,则出现阻塞。

//单客户版本,每次只能与一个用户建立通信连接public void Service(){while (true){Socket socket=null;try {//此处程序阻塞,监听并等待用户发起连接,有连接请求就生成一个套接字socket=serverSocket.accept();//本地服务器控制台显示客户连接的用户信息System.out.println("New connection accepted:"+socket.getInetAddress());BufferedReader br=getReader(socket);//字符串输入流PrintWriter pw=getWriter(socket);//字符串输出流pw.println("来自服务器消息:欢迎使用本服务!");String msg=null;//此处程序阻塞,每次从输入流中读入一行字符串while ((msg=br.readLine())!=null){//如果用户发送信息为”bye“,就结束通信if(msg.equals("bye")){pw.println("来自服务器消息:服务器断开连接,结束服务!");System.out.println("客户端离开。");break;}msg=msg.replace("?","!").replace("?","!").replace("吗","").replace("吗?","").replace("在","没");pw.println("来自服务器消息:"+msg);pw.println("来自服务器,重复消息:"+msg);}}catch (IOException e){e.printStackTrace();}finally {try {if (socket!=null)socket.close();//关闭socket连接以及相关的输入输出流}catch (IOException e){e.printStackTrace();}}}}

所以,根据上面的分析,将该单线程版本服务端与客户端通信对话的功能独立处理,由一个线程来处理。这样就不会阻塞主进程的执行。具体实现如下面。2、多线程版本
1、创建匿名内部类Handler,实现Runnable类的run方法,将通信对话放到run()里面:

class Handler implements Runnable {private Socket socket;public Handler(Socket socket) {this.socket = socket;}public void run() {//本地服务器控制台显示客户端连接的用户信息System.out.println("New connection accept:" + socket.getInetAddress());try {BufferedReader br = getReader(socket);PrintWriter pw = getWriter(socket);pw.println("From 服务器:欢迎使用服务!");String msg = null;while ((msg = br.readLine()) != null) {if (msg.trim().equalsIgnoreCase("bye")) {pw.println("From 服务器:服务器已断开连接,结束服务!");System.out.println("客户端离开。");break;}pw.println("From 服务器:" + msg);pw.println("来自服务器,重复消息:"+msg);}} catch (IOException e) {e.printStackTrace();} finally {try {if (socket != null)socket.close();} catch (IOException e) {e.printStackTrace();}}}}

2、使用newCachedThreadPool( )动态创建线程池
线程池作为成员变量:

//创建动态线程池,适合小并发量,容易出现OutOfMemoryErrorprivate ExecutorService executorService=Executors.newCachedThreadPool();

服务端的Service方法中创建新线程,交给线程池处理。

//多客户版本,可以同时与多用户建立通信连接public void Service() throws IOException {while (true){Socket socket=null;socket=serverSocket.accept();//将服务器和客户端的通信交给线程池处理Handler handler=new Handler(socket);executorService.execute(handler);}}

三、多用户与服务端通信演示
之前服务端只支持单用户通信对话时候,新用户发送的信息阻塞,服务器无法返回。

很有趣发现一点,另外一端结束通信,与此同时,另一端则立即收到服务器的回复信息。

从显示的时间上初步观察,可以判断之前发送的信息是阻塞在服务端进程,断开一方连接后,服务端才将阻塞队列的信息发送到客户端。那使用多线程之后,结果是怎么样呢?

动图演示进一步体会:

四、多用户服务器完整代码

/** TCPThreadServer.java* Copyright (c) 2020-11-14* author : Charzous* All right reserved.*/package chapter05;import java.io.*;import java.net.ServerSocket;import java.net.Socket;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class TCPThreadServer {private int port =8008;//服务器监听窗口private ServerSocket serverSocket;//定义服务器套接字//创建动态线程池,适合小并发量,容易出现OutOfMemoryErrorprivate ExecutorService executorService=Executors.newCachedThreadPool();public TCPThreadServer() throws IOException{serverSocket =new ServerSocket(8008);System.out.println("服务器启动监听在"+port+"端口...");}private PrintWriter getWriter(Socket socket) throws IOException{//获得输出流缓冲区的地址OutputStream socketOut=socket.getOutputStream();//网络流写出需要使用flush,这里在printWriter构造方法直接设置为自动flushreturn new PrintWriter(new OutputStreamWriter(socketOut,"utf-8"),true);}private BufferedReader getReader(Socket socket) throws IOException{//获得输入流缓冲区的地址InputStream socketIn=socket.getInputStream();return new BufferedReader(new InputStreamReader(socketIn,"utf-8"));}//多客户版本,可以同时与多用户建立通信连接public void Service() throws IOException {while (true){Socket socket=null;socket=serverSocket.accept();//将服务器和客户端的通信交给线程池处理Handler handler=new Handler(socket);executorService.execute(handler);}}class Handler implements Runnable {private Socket socket;public Handler(Socket socket) {this.socket = socket;}public void run() {//本地服务器控制台显示客户端连接的用户信息System.out.println("New connection accept:" + socket.getInetAddress());try {BufferedReader br = getReader(socket);PrintWriter pw = getWriter(socket);pw.println("From 服务器:欢迎使用服务!");String msg = null;while ((msg = br.readLine()) != null) {if (msg.trim().equalsIgnoreCase("bye")) {pw.println("From 服务器:服务器已断开连接,结束服务!");System.out.println("客户端离开。");break;}pw.println("From 服务器:" + msg);pw.println("来自服务器,重复消息:"+msg);}} catch (IOException e) {e.printStackTrace();} finally {try {if (socket != null)socket.close();} catch (IOException e) {e.printStackTrace();}}}}public static void main(String[] args) throws IOException{new TCPThreadServer().Service();}}

最后
本篇将解决了服务端多用户通信的问题,详细记录服务端多线程的实现,目标是多用户(客户端)能够同时与服务器建立连接并通信,避免阻塞,进一步完善TCP的Socket网络通信,运用Java多线程技术,实现多用户与服务端Socket通信!简而言之,相当于多用户访问服务器资源,服务器应该与各个客户端建立连接,就像我们日常使用QQ、微信、视频等客户端,就是多用户与服务器通信的例子。
老问题了,๑乛◡乛๑,好像完成这个之后,可以来实现一个什么有趣的呢?这里停留思考3秒!
……
……
……
就是:实现一个群组聊天房间,类似QQ、微信的群聊,可以多个用户之间的对话交流,是不是感觉挺有趣的。
————————————
本博文版权归作者所有!
禁止商业转载等用途或联系作者授权,非商业转载请注明出处!
作者:Charzueus 来源:博客园
本文链接:

https://www.cnblogs.com/chenzhenhong/p/13972517.html
版权声明:本文为博主原创文章,转载请附上原文出处链接和本声明。

服务端断开_Java多线程技术:实现多用户服务端Socket通信相关推荐

  1. JAVA物联所需技术_基于JAVA多线程技术解决物联云端服务雪崩效应的方法与流程...

    本发明涉及互联网技术领域,特别涉及一种基于JAVA多线程技术解决物联云端服务雪崩效应的方法. 背景技术: 目前,物联云系统已经作为普遍的智能电视平台出现在我们面前,而细致分析物联云系统我们可以发现,当 ...

  2. 基于TCP/IP协议的Java服务端与Android客户端的Socket通信及数据交互

    基于TCP/IP协议的Java服务端与Android客户端的Socket通信及数据交互 一.前言 1.Java服务端程序代码的项目名为TcpSocketServerOfJava,包名为com.exam ...

  3. 整理分享安徽省2022年技术先进型服务企业认定申报详细范围条件材料汇总

    关于安徽省2022年技术先进型服务企业认定申报的范围.条件.材料相关内容由于在"皖科高秘[2022]353号"通知和<安徽省技术先进型服务企业认定管理办法>上都有提及, ...

  4. java与c 通信_Java与C之间的socket通信

    最近正在开发一个基于指纹的音乐检索应用,算法部分已经完成,所以尝试做一个Android App.Android与服务器通信通常采用HTTP通信方式和Socket通信方式.由于对web服务器编程了解较少 ...

  5. 简易 IM 双向通信电脑端 GUI 应用——基于 Netty、WebSocket、JavaFX 、多线程技术等

    简易 IM 双向通信电脑端 GUI 应用--基于 Netty.WebSocket.JavaFX .多线程技术等 说明 运行效果 核心代码 完整代码 参考知识 说明   这是一款使用 Netty 来实现 ...

  6. 简易 IM 双向通信电脑端 GUI 应用——基于 Netty、JavaFX、多线程技术等

    简易 IM 双向通信电脑端 GUI 应用--基于 Netty.JavaFX.多线程技术等 说明 运行效果 核心代码 完整代码 参考知识 说明   这是一个使用 Netty 来实现 IM 双向通信的 d ...

  7. 服务端渲染(SSR) 通用技术解决方案

    项目背景 服务端渲染(SSR) 通用技术解决方案的诞生来源于对 360搜索百科移动端项目的一次重构实践.而当时决定重构该项目的主要原因有以下几点: 1.  技术栈陈旧,熟悉.开发以及维护成本都较高 项 ...

  8. 软件及互联网高端灵活用工与技术服务提供商

    迦太利华于2013年创立于黔南惠水百鸟河数字小镇,是贵州高端灵活用工.服务外包.软件与互联网外包的开创者,是国内发展最快的软件与互联网外包服务企业之一,已在贵阳.北京.上海.深圳.成都.杭州.青岛.广 ...

  9. 奇迹mu服务端架设开服技术教程

    奇迹mu服务端架设开服技术教程 服务端.服务器.域名都准备好后我们需要怎么操作: 1,安装MS-SQL2000(微软的数据库服务器) 2,还原奇迹服务端中的数据库文件 3,设置服务端中IP及其数据源 ...

最新文章

  1. 教你编写Node.js中间件,实现服务端缓存
  2. Androidstudio坑
  3. 使用 Mesos 管理虚拟机
  4. matlab两个图共用一个x轴_Matlab Figures (3) —— 叠加作图与多坐标轴
  5. EMQX源码阅读笔记
  6. mtk 驱动(55)---mtk指纹移植
  7. centos7 修改时区
  8. 十款大名鼎鼎的开源软件
  9. ajax获取信息发送短信,javascript ajax获取信息功能代码
  10. X11/XWINDOW GUI窗口应用在任务栏上没有显示的解决办法
  11. SAP从入门到精通 知识体系
  12. 苹果微信默认字体样式
  13. Pr视频剪辑出现红线
  14. 快速有效分离RNA——土壤RNA纯化试剂盒
  15. linux 系统挂载ISO 文件
  16. word wps 出版 常用操作
  17. 计算机如何连接wifi台式,台式电脑怎么连wifi
  18. java中获取中文拼音(全拼)和中文首字母
  19. w ndows英文读音,Windows是什么意思
  20. swd只能下载一次第二次出现错误

热门文章

  1. 【英语学习】【Daily English】U02 Daily Routine L01 Sadly, my schedule is very tight.
  2. C# winform程序怎么打包成安装项目(图解)
  3. /usr/bin/python^M: bad interpreter: No such file or directory
  4. 安装了email模块还是报错_官网的Pyngl和Pynio安装方法会报错!正确的在这里!
  5. ie不加载jre_详细讲解!从JVM直到类加载器
  6. 易语言数据类型与c 对照,易语言利用自定义数据类型和数组. 制作键对值操作类/内存配置...
  7. 【音效处理】Delay/Echo 简介
  8. linux下的正则表达式
  9. MVC Controller中View(model)如何在 View中的index页面获得?
  10. C# 从DataTable中取值