JavaEE|网络编程之套接字 TCP
文章目录
- 一、ServerSocket API
- 构造方法
- 常用方法
- 二、Socket API
- 构造方法
- 常用方法
- 注意事项
- 三、TCP中的长短连接
- E1:一发一收(短连接)
- E2:请求响应(短连接)
- E3:多线程下的TCP回响服务器
说明:这部分说实话有点懵,理解上有点吃力,这里暂时先放到这,有新的认识再进行回来修改。
一、ServerSocket API
它是创建TCP服务端Socket的api
构造方法
方法签名 | 说明 |
---|---|
ServerSocket(int port) | 创建一个服务端流套接字Socket,并绑定到指定端口 |
给服务器绑定端口。
常用方法
方法签名 | 说明 |
---|---|
Socket accept() | 开始监听创建时绑定的端口,有客户端连接后,返回一个服务端Socket 对象,并基于该Socket建立与客户端的连接,否则阻塞等待 |
void close() | 关闭此套接字 |
二、Socket API
即会给客户端和服务器使用。
构造方法
方法签名 | 说明 |
---|---|
Socket(String host, int port) | 创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的 进程建立连接 |
常用方法
方法签名 | 说明 |
---|---|
InetAddress getInetAddress() | 返回套接字所连接的地址 |
InputStream getInputStream() | 返回此套接字的输入流 |
OutputStream getOutputStream() | 返回此套接字的输出流 |
TCP中,socket对象,对于服务器而言,是靠accpet返回的;对于客户端而言,是靠代码内部构造的。
注意事项
-
TCP 中的ClientSocket的socket对象需要释放,而前边Server对象和UDP的都没释放,为什么这里需要呢?原因有二
1.这里的socket声明周期比较短,UDP里边的和TCP服务器里的是要跟随整个程序的。
2.这里的socket对象可能比较多,可能会把文件描述符表占满。
outputStream相当于一个文件描述符(一个socket文件),通过这个对象就可以往这个文件描述符中写数据。
OutStream自身方法不方便写字符串,把流进行转换一下,用一个PW对象来表示(对应的文件还是通过一个)。
不过使用PW(打印流)写,往一个地方写,只不过的写的更方便了。
println是写,往控制台上,往网卡上……
三、TCP中的长短连接
客户端socket对象构造,会触发tcp建立连接
短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据。
长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据。
两者区别如下:
建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。
两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于客户端与服务端通信频繁的场景,如聊天室,实时游戏等。
E1:一发一收(短连接)
服务器端代码、客户端代码
public class Code04_TCPEchoServer {private ServerSocket serverSocket=null;//这种可以返回Socket类型的对象public Code04_TCPEchoServer(int port) throws IOException {serverSocket=new ServerSocket(port);}public void start() throws IOException {System.out.println("启动服务器成功!");while(true){Socket clientSocket=serverSocket.accept();//效果是接收连接//前提是客户端来建立连接:若有则连接,若无,则阻塞等待//建立连接processConnection(clientSocket);}}//使用这个方法来处理一个连接//这个连接对应到一个客户端,但是这里可能会设计到多次交互private void processConnection(Socket clientSocket) {System.out.printf("[%s:%d] 客户端上线!",clientSocket.getInetAddress().toString(),clientSocket.getPort());//基于上述socket进行通信try(InputStream inputStream=clientSocket.getInputStream();//由于要处理多个请求,所以也是使用循环来进行OutputStream outputStream=clientSocket.getOutputStream()){while(true){//1.读取请求Scanner scanner=new Scanner(inputStream);if(!scanner.hasNext()){
// System.out.println("当前连接已关闭!");System.out.printf("[%s:%d] 客户端下线!",clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}System.out.println();String request=scanner.next();//next读到换行符/其他空白符结束,但是不包含//2.根据请求构造响应String response=process(request);//3.返回响应结果PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);// 此处加上 flush 保证数据确实发送出去了.printWriter.flush();//4.打印中间结果System.out.printf(response);}} catch (IOException e) {e.printStackTrace();}finally {try{clientSocket.close();} catch (IOException e) {e.printStackTrace();}}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {Code04_TCPEchoServer tcpEchoServer=new Code04_TCPEchoServer(1200);tcpEchoServer.start();}
}
public class Code05_TCPEchoClient {private Socket socket = null;//这是用来接收服务器的socket对象public Code05_TCPEchoClient(String serverIp, int serverPort) throws IOException {// Socket 构造方法, 能够识别 点分十进制格式的 IP 地址. 比 DatagramPacket 更方便.// new 这个对象的同时, 就会进行 TCP 连接操作.socket = new Socket(serverIp, serverPort);}public void start() {System.out.println("客户端启动!");Scanner scanner = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while (true) {// 1. 先从键盘上读取用户输入的内容System.out.print("> ");String request = scanner.next();if (request.equals("exit")) {System.out.println("bye");break;}// 2. 把读到的内容构造成请求, 发送给服务器.PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);// 此处加上 flush 保证数据确实发送出去了.printWriter.flush();// 3. 读取服务器的响应Scanner respScanner = new Scanner(inputStream);String response = respScanner.next();// 4. 把响应内容显示到界面上System.out.println(response);}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {Code05_TCPEchoClient client = new Code05_TCPEchoClient("127.0.0.1", 1200);client.start();}
}
这里不用println写是不行的,原因如下:
TCP协议是面向字节流的协议。接收方一次读多少个字节需要我们在数据传输中进行明确约定。
这里的next和println是相互制约的。next在等请求中的结束符。
enter是换行符,但是这里按下enter是把next里内容送上去,并没有把换行符读到。
E2:请求响应(短连接)
略
与UDP类似,这里是在服务器处,加上了相关的业务逻辑。
E3:多线程下的TCP回响服务器
public class Code04_TCPEchoServer {private ServerSocket serverSocket=null;//这种可以返回Socket类型的对象public Code04_TCPEchoServer(int port) throws IOException {serverSocket=new ServerSocket(port);}public void start() throws IOException {System.out.println("启动服务器成功!");ExecutorService threadPool= Executors.newCachedThreadPool();while(true){Socket clientSocket=serverSocket.accept();//效果是接收连接//前提是客户端来建立连接:若有则连接,若无,则阻塞等待//建立连接threadPool.submit(()->{processConnection(clientSocket);});}}//使用这个方法来处理一个连接//这个连接对应到一个客户端,但是这里可能会设计到多次交互private void processConnection(Socket clientSocket) {System.out.printf("[%s:%d] 客户端上线!",clientSocket.getInetAddress().toString(),clientSocket.getPort());//基于上述socket进行通信try(InputStream inputStream=clientSocket.getInputStream();//由于要处理多个请求,所以也是使用循环来进行OutputStream outputStream=clientSocket.getOutputStream()){while(true){//1.读取请求Scanner scanner=new Scanner(inputStream);if(!scanner.hasNext()){
// System.out.println("当前连接已关闭!");System.out.printf("[%s:%d] 客户端下线!",clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}System.out.println();String request=scanner.next();//next读到换行符/其他空白符结束,但是不包含//2.根据请求构造响应String response=process(request);//3.返回响应结果PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);// 此处加上 flush 保证数据确实发送出去了.printWriter.flush();//4.打印中间结果System.out.printf(response);}} catch (IOException e) {e.printStackTrace();}finally {try{clientSocket.close();} catch (IOException e) {e.printStackTrace();}}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {Code04_TCPEchoServer tcpEchoServer=new Code04_TCPEchoServer(1200);tcpEchoServer.start();}
}
1.修改允许多个客户端其中之后服务器只显示一个客户端上线
2.客户端1发送消息可以,客户端2发送消息没有响应【占线】
一旦客户端1一下线,客户端2立即上线。
为什么?这里需要我们结合服务器的启动代码分析
这里是多线程的问题。(其实还是有点不太懂,但具体是哪里说不上来)
当有客户端连上服务器后,代码就执行到了processConnection这个方法里的while循环,这时另一个客户端再次尝试发送请求,由于此时调到这里循环不结束,processConnection方法就结束不了,进一步也就无法再次accept了
解决办法:使用多线程。
主线程。专门负责accpet,每次收到一个连接,创建新线程,由这个新线程负责这个新的客户端
这里因为有可能频繁的申请释放线程,所以这里我们采用的是线程池。
一般的版本:
Thread t=new Thread(()->{processConnection(clientSocket); }); t.start();
说明:虽然线程池的加入会一定程度上解决多个客户端的需要同时启动的效率问题。但是线程的创建与销毁始终还是比较耗时间的。一旦客户端的数量激增接近阈值,还是存在的问题的。
对此,操作系统提供了io多路复用的机制缓解。
【基于BIO(同步阻塞IO)的长连接会一直占用系统资源。对于并发要求很高的服务端系统来说,这样的消耗是不能承受的。实际应用时,服务端一般是基于NIO(即同步非阻塞IO)来实现长连接,性能可以极大的提升。】
相关文章:

JavaEE|网络编程之套接字 TCP
文章目录一、ServerSocket API构造方法常用方法二、Socket API构造方法常用方法注意事项三、TCP中的长短连接E1:一发一收(短连接)E2:请求响应(短连接)E3:多线程下的TCP回响服务器说明:这部分说实话有点懵&a…...

Robot Framework自动化测试---元素定位
不要误认为Robot framework 只是个web UI测试工具,更正确的理解Robot framework是个测试框架,之所以可以拿来做web UI层的自动化是国为我们加入了selenium2的API。比如笔者所处工作中,更多的是拿Robot framework来做数据库的接口测试…...
ASP.NET Core中的路由
传统路由 app.MapControllerRoute( name: "default", pattern: "{controllerHome}/{actionIndex}/{id?}"); MapControllerRoute用于创建单个路由。 单个路由命名为 default 路由 。大多数具有控制器和视图的应用都使用类似 default 路由的路由模板。 之所…...

VBA提高篇_26 Textbox多行_ListBox_ComboBox
文章目录1. 文本框多行换行2. ListBox: 列表框2.1 列表框中添加条目的三种方法:3. ComboBox 组合框: 属性方法等同于以上ListBox1. 文本框多行换行 MultiLine: 控制文本框多行自动换行() Enterkeybehevior: True 代表允许在文本框中使用回车键换行 WordWrap: True 代表自动换…...

python环境配置
python环境配置一、ADB环境配置1、ADB下载路径:2、点击下载3、解压并放到本地磁盘4、配置ADB环境变量二、Python环境配置1、Python下载路径:2、点击下载(默认下载最新的)3、解压并放到本地磁盘4、配置Python环境变量5、配置pip环境变量三、Pycharm安装1、pycharm下载路径:2、点…...

集算器连接外部库
1. 配置jar包将以下jar包从报表的类路径(【安装根目录】\report\lib或【安装根目录】\report\web\webapps\demo\WEB-INF\lib)中拷贝到集算器目录(【安装根目录】\esProc\ extlib\mongoCli);润乾外部库核心jar为:scu-mo…...

力扣刷题|216.组合总和 III、17.电话号码的字母组合
文章目录LeetCode 216.组合总和题目链接🔗思路LeetCode 17.电话号码的字母组合题目链接🔗思路LeetCode 216.组合总和 题目链接🔗 LeetCode 216.组合总和 思路 本题就是在[1,2,3,4,5,6,7,8,9]这个集合中找到和为n的k个数的组合。 相对于7…...

机器学习笔记之谱聚类(一)k-Means聚类算法介绍
机器学习笔记之谱聚类——K-Means聚类算法介绍引言回顾:高斯混合模型聚类任务基本介绍距离计算k-Means\text{k-Means}k-Means算法介绍k-Means\text{k-Means}k-Means算法示例k-Means\text{k-Means}k-Means算法与高斯混合模型的关系k-Means\text{k-Means}k-Means算法的…...

云原生周刊 | 2023 年热门:云 IDE、Web Assembly 和 SBOM | 2023-02-20
在 CloudNative SecurityCon 上,云原生计算基金会的首席技术官 Chris Aniszczyk 在 The New Stack Makers 播客的这一集中强调了 2023 年正在形成几个趋势: 随着 GitHub 的 Codespaces 平台通过集成到 GitHub 服务中获得认可,云 IDE…...

python 打包EXE
注: 从个人博客园 移植而来 环境: Windows7 Python 2.7 参考: 使用pyinstaller打包python程序 Pyinstaller 打包发布经验总结 Using PyInstaller 简介 使用python引用第三方的各种模块编写一个工具后,如果想发给其他人&…...

CANopen概念总结、心得体会
NMT网络管理报文: NMT 主机和 NMT 从机之间通讯的报文就称为 NMT 网络管理报文。常见报文说明: 0101---------------网络报文发送Nmt_Start_Node,让电机进入OP模式(此时还不会发送同步信号) setState(d, Operational)------------------开启…...

【2】MYSQL数据的导入与导出
文章目录 MYSQL-库(相同库名称)的导入导出MYSQL-库(不同库名称)的导入导出MYSQL-表的导入导出MYSQL-表的指定查询记录导入导出前提: 客户端工具是:SQLyog MYSQL-库(相同库名称)的导入导出 1、选中指定库——右键,选择【将数据库复制到不同的主机/数据库】 2、选中指…...

Kaggle系列之CIFAR-10图像识别分类(残差网络模型ResNet-18)
CIFAR-10数据集在计算机视觉领域是一个很重要的数据集,很有必要去熟悉它,我们来到Kaggle站点,进入到比赛页面:https://www.kaggle.com/competitions/cifar-10CIFAR-10是8000万小图像数据集的一个子集,由60000张32x32彩…...

ESP-C3入门11. 创建最基本的HTTP请求
ESP-C3入门11. 创建最基本的HTTP请求一、menuconfig配置二、配置 CMakeLists1. 设置项目的额外组件目录2. 设置头文件搜索目录三、在 ESP32 上执行 HTTP 请求的基本步骤1. 创建 TCP 连接2. 设置 HTTP 请求3. 发送 HTTP 请求4. 接收 HTTP 响应5. 处理 HTTP 响应6. 关闭 TCP 连接…...

K8S+Jenkins+Harbor+Docker+gitlab集群部署
K8SJenkinsHarborDockergitlab服务器集群部署 目录K8SJenkinsHarborDockergitlab服务器集群部署1.准备以下服务器2.所有服务器统一处理执行2.1 关闭防火墙2.2 关闭selinux2.3 关闭swap(k8s禁止虚拟内存以提高性能)2.4 更新yum (看需要更新)2.5 时间同步2…...

看见统计——第四章 统计推断:频率学派
看见统计——第四章 统计推断:频率学派 接下来三节的主题是中心极限定理的应用。在不了解随机变量序列 {Xi}\{X_i\}{Xi} 的潜在分布的情况下,对于大样本量,中心极限定理给出了关于样本均值的声明。例如,如果 YYY 是一个 N(0&am…...

2023年2月访问学者博士后热门国家出入境政策变化汇总
近期关于出国的咨询量日益增多,出入境政策也是其中之一。所以本期知识人网小编汇总了最新访问学者和博士后关注的热门国家及地区入境政策变化,提供给大家。目前各国入境政策大致分为三种:一、 无法入境的国家如:摩洛哥、朝鲜等。二…...

“离开浪浪山”是假象,80%年轻人下班后还在学习,真实是想先上个山。
最近,又有一个关于年轻人与职场的新词横空出世—— 浪浪山。 什么是浪浪山? 每个人心中都有一座浪浪山。 浪浪山,其实是人生的一种状态,步入社会时满腔热血,然而很快就被现实给修理了一顿;想要辞职不干出去…...

Kotlin 33. CompileSdkVersion 和 targetSdkVersion 有什么区别?
CompileSdkVersion 和 targetSdkVersion 有什么区别? 在 build.gradle (Module) 文件中,我们通常会看到 CompileSdkVersion 和 targetSdkVersion 的使用,比如下面是一个完整的 build.gradle (Module) 文件: plugins {id com.and…...

实用调试技巧——“C”
各位CSDN的uu们你们好呀,今天小雅兰的内容是实用调试技巧,其实小雅兰一开始,也不知道调试到底是什么,一遇到问题,首先就是观察程序,改改这里改改那里,最后导致bug越修越多,或者是问别…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...

【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...

如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...