Java的Socket通信的断网重连的正确写法
Java的Socket通信的断网重连的正确写法
- Socket通信的断网重连介绍
- 客户端与服务端源码
- 演示截图
- 本地演示
- 服务器演示
- 演示截图
- 总结
Socket通信的断网重连介绍
针对于已经建立通信的客户端与服务器,当客户端与服务器因为网络问题导致网络不通而断开连接了或者由于服务器端的服务被突然停掉,而客户端进行的一种尝试重新建立连接的操作;我采用的是Socket自带的往通道内写数据是否成功来判断当前连接是否断开,采用该方式的好处是简洁易懂,高效通用。
一般的采用ping命令,定时尝试重新建立新的连接的方式,都有一些不足之处,前者是没办法针对端口进行判断,效果不好;后者则是每次都建立新的连接,导致服务器端压力会较大,而且相对的代码逻辑也会更加复杂。而采用本文介绍的写数据的方式,即可简单判断连接是否断开;原理是当连接断开后,写数据时会报错,捕获该错误即可;底层原理则是Java的Socket底层代码,采用C语言或者C++编写,在那里肯定是去判断IP和端口是否可以访问到的逻辑;有需要的话,下篇文章可以查看源码,进一步熟悉Java的网络编程知识。
客户端与服务端源码
为了方便演示和理解,仅进行了服务端向客户端发送数据,客户端接收数据的单向通信方式;实际扩展也非常简单。可以由读者进行尝试实现,增加网络编程知识的熟练度。
服务端
package com;import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;/*** @author BBYH*/
public class MyServerSocket {public static final Integer PORT = 8080;private static Socket myServerSocket;private static OutputStream outputStream;public static void listen() {System.out.println("服务端监听端口" + PORT);new Thread(() -> {try (ServerSocket serverSocket = new ServerSocket(PORT)) {while (true) {try {myServerSocket = serverSocket.accept();System.out.println("服务端接收到来自客户端的连接");outputStream = myServerSocket.getOutputStream();new Thread(() -> {Scanner scanner = new Scanner(System.in);while (true) {try {System.out.println("向客户端发送消息:");String sendContent = scanner.next();outputStream.write(sendContent.getBytes(StandardCharsets.UTF_8));} catch (Exception e) {e.printStackTrace();}}}).start();} catch (IOException e) {throw new RuntimeException(e);}}} catch (IOException e) {e.printStackTrace();}}).start();}public static void main(String[] args) {listen();}
}
客户端
package com;import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Date;/*** @author BBYH* @description 通过socket的写数据,来判断当前的socket是否连通*/
public class ClientSocket {public static final String IP = "127.0.0.1";public static final Integer PORT = 8080;private static Socket socket;private static InputStreamReader reader;private static OutputStream outputStream;public static void main(String[] args) {// 首次建立连接connect();}public static void connect() {System.out.println("向服务端端口" + PORT + "申请建立连接");try {socket = new Socket(IP, PORT);System.out.println("客户端与服务器端连接建立成功");reader = new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8);outputStream = socket.getOutputStream();// 开启读取线程openReadThread();} catch (Exception e) {e.printStackTrace();}}private static void openReadThread() {new Thread(() -> {// 开启断网重连线程new Thread(() -> {while (true) {if (isDisContentWithServer()) {while (true) {try {socket = new Socket(IP, PORT);reader = new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8);outputStream = socket.getOutputStream();System.out.println(new Date() + ":重新建立连接成功");break;} catch (IOException e) {System.out.println(new Date() + ":尝试重新建立连接失败");try {Thread.sleep(3000);} catch (InterruptedException ex) {throw new RuntimeException(ex);}}}}}}).start();char[] readBuf = new char[1024];while (true) {try {if (reader.ready()) {int read = reader.read(readBuf);System.out.println("接收到来自服务端的消息:" + new String(readBuf, 0, read));}} catch (Exception e) {e.printStackTrace();}}}).start();}public static boolean isDisContentWithServer() {try {outputStream.write(("发送数据").getBytes(StandardCharsets.UTF_8));Thread.sleep(3000);return false;} catch (Exception e) {return true;}}
}
尽管在客户端开启断网重连线程中进行了两次while循环,不是很优雅,但仍然可以较为清晰的理解到代码的执行逻辑;即,每隔固定时间(3秒)进行是否连通的判断,当发现不连通的,则进行尝试重连(重新建立连接),该处的逻辑没有办法省略,由于客户端一般不长时间运行,消耗的资源虽然较多,但在程序运行结束后也自然就释放了。
演示截图
演示流程为:开启服务器 – 客户端建立连接 – 服务器发送一些数据 – 服务器断开连接 – 客户端尝试重连(自动进行) – 重新开启服务器 – 服务器再次发送数据
在该过程中,服务器在首次开启后的关闭,即代表了客户端的断网,实际情况中可以采用服务器,然后采用断开Wifi的方式代替这个关闭服务器,只要保证了客户端与服务器无法连通,即代表断网了,后面的重连则可以采用再次打开Wifi,重新连接上网络,连接则自动建立好
本地演示
开启服务器 – 客户端建立连接 – 服务器发送一些数据
服务器断开连接 – 客户端尝试重连(自动进行)
重新开启服务器 – 服务器再次发送数据
服务器演示
采用的是我申请的阿里云服务器,流程与上述文字说明一致,采用断开Wifi的形式来代替服务器关闭的效果;服务器关闭同样被我测试过,与本地一样,可以进行重连。由于我采用Xshell进行连接,当断开连接后日志会失效,所以采用后台任务记录运行打印的日志;命令为 nohup java com.MyServerSocket > MyServerSocket.out &
关于不采用防火墙来演示断网效果,则是因为防火墙无法拦截已经建立好的Socket通道,经测试发现该现象,读者可手动进行验证,如有意外情况,可向我进行反馈。
由于nohup命令的输入重定向,我暂时还没研究明白,所以目前服务端也不进行发送数据,两边都只是简单的建立连接和断开,代码进行了简单的调整,如下:
服务器端
package com;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** @author BBYH*/
public class MyServerSocket {public static final Integer PORT = 8080;private static Socket myServerSocket;public static void listen() {System.out.println("服务端监听端口" + PORT);new Thread(() -> {try (ServerSocket serverSocket = new ServerSocket(PORT)) {while (true) {try {myServerSocket = serverSocket.accept();System.out.println("服务端接收到来自客户端的连接");} catch (IOException e) {throw new RuntimeException(e);}}} catch (IOException e) {e.printStackTrace();}}).start();}public static void main(String[] args) {listen();}
}
客户端
package com;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Date;/*** @author BBYH* @description 通过socket的写数据,来判断当前的socket是否连通*/
public class ClientSocket {public static final String IP = "127.0.0.1";public static final Integer PORT = 8080;private static Socket socket;private static OutputStream outputStream;public static void main(String[] args) {// 首次建立连接connect();}public static void connect() {System.out.println("向服务端端口" + PORT + "申请建立连接");try {socket = new Socket(IP, PORT);System.out.println("客户端与服务器端连接建立成功");outputStream = socket.getOutputStream();// 开启断网重连线程openReConnectThread();} catch (Exception e) {e.printStackTrace();}}private static void openReConnectThread() {new Thread(() -> {while (true) {try {if (isDisContentWithServer()) {while (true) {try {socket = new Socket(IP, PORT);outputStream = socket.getOutputStream();System.out.println(new Date() + ":重新建立连接成功");break;} catch (IOException e) {System.out.println(new Date() + ":尝试重新建立连接失败");try {Thread.sleep(2000);} catch (InterruptedException ex) {throw new RuntimeException(ex);}}}}} catch (Exception e) {e.printStackTrace();}}}).start();}public static boolean isDisContentWithServer() {try {outputStream.write(("发送数据").getBytes(StandardCharsets.UTF_8));Thread.sleep(2000);return false;} catch (Exception e) {return true;}}
}
演示截图
开启服务器 – 客户端建立连接
断开Wifi – 客户端尝试重新建立连接 – 重新打开Wifi – 连接成功
总结
本次断网重连演示完美结束,如有疑问,可在评论区进行提问
相关文章:

Java的Socket通信的断网重连的正确写法
Java的Socket通信的断网重连的正确写法 Socket通信的断网重连介绍客户端与服务端源码演示截图本地演示服务器演示演示截图 总结 Socket通信的断网重连介绍 针对于已经建立通信的客户端与服务器,当客户端与服务器因为网络问题导致网络不通而断开连接了或者由于服务器…...

Rocketmq--消息发送和接收演示
使用Java代码来演示消息的发送和接收 <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.0.2</version> </dependency> 1 发送消息 消息发送步骤: 创建…...

ArcGIS Pro将SHP文件转CAD并保留图层名称
相信大家应该都使用过ArcGIS将SHP文件转CAD格式,转换过后所有的要素都在一个图层内,那么有没有办法将SHP文件某个字段的值作为CAD的图层名字呢,答案是肯定的,这里就为大家介绍一下ArcGIS Pro转CAD文件并且保留图层名称的方法&…...
GEE:使用for循环合成时间序列影像
作者:CSDN @ _养乐多_ 在本博客中,我们将介绍如何使用Google Earth Engine创建一个时间序列图像集合,以便进行时间序列分析或生成动态图像。 文章目录 一、核心代码二、代码解释三、示例代码链接一、核心代码 // 创建一个空的 image 图像集合 var imagelist = ee.List([])…...
flink1.13.2版本的对应的hive的Hcatalog的使用记录
依赖版本要求<hive.version>3.1.2</hive.version><flink.version>1.13.2</flink.version><hadoop.version>3.3.2</hadoop.version><scala.binary.version...

STM32 ADC介绍和应用
目录 1.ADC是什么? 2.ADC的性能指标 3.ADC特性 4.ADC通道 5.ADC转换顺序 6.ADC触发方式 7.ADC转化时间 8.ADC转化模式 扫描模式 单次转换/连续转换 9.ADC实验 使用ADC读取烟雾传感器的值 代码实现思路: 1.ADC是什么? 全称&#…...

vue项目打包_以生产环境prod模式打包_vue-cli-service 不是内部或外部命令,也不是可运行的程序---vue工作笔记0025
打开命令行: 首先执行npm install 不执行会报错: npm run build:prod --scripts-prepend-node-pathauto 然后再这样执行就是以生产环境模式打包了....
FreeSWITCH的liberal dtmf
sip profile配置liberal-dtmf为true,或者通道变量rtp_liberal_dtmf为true,其含义就是不挑剔协商的DTMF,offer rfc2833并接受远端的rfc2833 和SIP INFO。 sofia.c的部分内容: // 收到sip info的处理 void sofia_handle_sip_i_inf…...

透明度模糊Android实现
最近有个需求,需要透明度加模糊,并且无法通过Glide的方式实现。研究后发现有一个第三方库可以实现这个效果 implementation com.github.Dimezis:BlurView:version-2.0.3在activity的onCreate()方法中 实现效果 可以看到上边的bar…...

JavaScript学习笔记04
JavaScript笔记04 方法 定义方法 当一个函数是一个对象的属性时,称之为方法。例: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><script>let p…...
18 Python的sys模块
概述 在上一节,我们介绍了Python的os模块,包括:os模块中一些常用的属性和函数。在这一节,我们将介绍Python的sys模块。sys模块提供了访问解释器使用或维护的变量,以及与解释器进行交互的函数。 通俗来讲,sy…...

Spring Boot 各版本的支持时间
1. Spring Boot 各版本的支持时间 Spring Boot 2.7 的版本,支持到2023-11-18,之后就要停止支持了。 按照官网的数据,3.0 的版本也是到2023年11月就停止支持了。如果要转到SpringBoot3,直接从3.1开始吧。到写这篇文章时ÿ…...

华为云云耀云服务器L实例评测|Git 私服搭建指南
前言 本文为华为云云耀云服务器L实例测评文章,测评内容是 云耀云服务器L实例 Git 私有服务器搭建指南 系统配置:2核2G 3M Ubuntu 20.04 我们平时在使用代码托管服务的时候,可能某些代码托管平台对成员有限制,或是由于内容原因会对…...
Linux下的Swap内存
目录 一、Swap简介二、Swap内存查看三、Swap内存释放1、关闭swap2、查看关闭进度2、开启swap 一、Swap简介 swap space 是磁盘上的一块区域,可以是一个分区,也可以是一个文件。所以具体的实现可以是 swap分区 也可以是 swap文件。 当系统物理内存吃紧时…...

Unity中程序集dll
一:前言 一个程序集由一个或多个文件组成,通常为扩展名.exe和.dll的文件称为程序集,.exe是静态的程序集,可以在.net下直接运行加载,因为exe中有一个main函数(入口函数),.dll是动态链接库&#…...
识典百科取代快懂百科,如何在识典百科创建词条?
我们一个营销项目里面有四个百科词条的创建,在执行过程中遇见了快懂百科升级,创建词条请前往识典百科,看这个意思字节跳动是要把快懂百科升级整合到识典百科了。 快懂百科升级整合进入识典百科 近年来,字节跳动动作不断࿰…...
入门python
[NOIP2006 普及组] 明明的随机数 题目描述 明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了 N N N 个 1 1 1 到 1000 1000 1000 之间的随机整数 ( N ≤ 100 ) (N\leq100) (N≤100),对于其中重复的数字…...

基于vue的黑马前端项目小兔鲜
目录 项目学习 初始化项目 建立项目 引入elementplus elementPlus主题设置 配置axios 路由 引入静态资源 自动导入scss变量 Layout页 组件结构快速搭建 字体图标渲染 一级导航渲染 吸顶导航交互实现 Pinia优化重复请求 Home页 分类实现 banner轮播图 …...
细节决定成败!jdbc的List<?> qryList4Sql(String sql)报错-标志符过长
问题产生背景: 在写sql时,想着简单直接就偷懒了,没有看清细节 操作步骤跟发现问题: 1. sql语句的执行选用的是jdbc提供的List<?> qryList4Sql(String sql) 方法 2,这是我的sql语句(简化处理) String sql "…...

ChatGLM Pytorch从0编写Transformer算法
预备工作 # !pip install http://download.pytorch.org/whl/cu80/torch-0.3.0.post4-cp36-cp36m-linux_x86_64.whl numpy matplotlib spacy torchtext seaborn import numpy as np import torch import torch.nn as nn import torch.nn.functional as F import math, copy, tim…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...