当前位置: 首页 > article >正文

【网络编程】从零开始彻底了解网络编程(三)

在这里插入图片描述

本篇博客给大家带来的是网络编程的知识点.
🐎文章专栏: JavaEE初阶
🚀若有问题 评论区见
欢迎大家点赞 评论 收藏 分享
如果你不知道分享给谁,那就分享给薯条.
你们的支持是我不断创作的动力 .

王子,公主请阅🚀

  • 要开心
    • 要快乐
      • 顺便进步
  • TCP流套接字编程

要开心

要快乐

顺便进步

TCP流套接字编程

TCP 的 socket API 和 UDP 的 socket API 差异很大.
但是和的文件操作有密切联系.
TCP中关键的类:
① ServerSocket: 给服务器使用的类,使用这个类来绑定端口号.
② Socket: 既会给服务器用,又会给客户端用.
这两个类抽象了网卡这样的硬件设备.

1. ServerSocket
ServerSocket 是创建TCP服务端的API。
ServerSocket 构造方法:

在这里插入图片描述

2. ServerSocket 方法:

ServerSocket 方法:
在这里插入图片描述
如果有客户端, 和服务器建立连接,这个时候服务器的应用程序是不需要做出任何操作(也没有任何感知的),内核直接就完成了连接建立的流程(三次握手).完成流程之后,就会在内核的队列中排队(每个serverSocket 都有一个这样的队列). 应用程序要想和这个客户端进行通信,就需要通过一个 accept 方法把内核队列里已经建立好的连接对象,拿到应用程序中.

3. Socket

Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。
不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。
Socket 构造方法:

在这里插入图片描述
Socket 方法:

在这里插入图片描述
前面的文章说过,TCP是字节流通信方式.
这里的InputStream 和 OutputStream 就是 字节流!!!
可以借助这俩对象,完成数据的"发送"和"接收"通过 InputStream 进行 read 操作,就是"接收".
通过 OutputStream 进行 write 操作, 就是"发送" .

4. 利用TCP实现一个回显的程序:

服务器:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;public class TcpEchoServer {private ServerSocket serverSocket;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");while(true) {//1. 通过accept方法,把内核中已经建立好的连接拿到应用程序.Socket clientSocket = serverSocket.accept();//2. 处理一个连接的逻辑.processConnection(clientSocket);}}public void processConnection(Socket clientSocket) {//打印一个日志,表示有客户端连上了.System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());//读取请求,根据请求计算响应,最后返回响应//Socket 对象内部包含了两个字节流对象,把InputStream(读取),OutputStream(发送)获取到,完成后续的读写.try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {//一次连接中,可能会涉及多次请求和响应while(true) {//1. 读取请求并解析Scanner scanner = new Scanner(inputStream);if(!scanner.hasNext()) {//没有下一行,说明读取完毕,客户端下线System.out.printf("[%s:%d] 客户端下线",clientSocket.getInetAddress(),clientSocket.getPort());break;}//暗含一个约定: scanner遇到空白符(\n)就返回.//和客户端那里相呼应.String request = scanner.next();//2. 根据请求计算响应String response = process(request);//3. 将响应发给客户端,利用PrinterWriter包裹OutputStreamPrintWriter writer = new PrintWriter(outputStream);//使用PrintWriter的println方法,把响应返回给客户端//此处用println,而不是print就是为了结尾加上\n,与客户端对应.writer.println(response);writer.flush();//4. 打印日志,表示当前请求的情况.System.out.printf("[%s:%d] req: %s, resp: %s\n",clientSocket.getInetAddress(),clientSocket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9090);server.start();}
}

在这里插入图片描述

空白符是一类特殊的字符,有 换行, 回车符,空格, 制表符,翻页符, 垂直制表符…等等。客户端发起的请求,此处会以空白符作为结束标记(此处就约定使用 \n)


客户端:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;public class TcpEchoClient {private Socket socket = null;public TcpEchoClient(String serverIp,int serverPort) throws IOException {//在创建socket的同时,和服务器建立"连接"此时就得告诉Socket服务器在哪里//所以需要传服务器 ip 和 端口号.socket = new Socket(serverIp,serverPort);}public void start() {System.out.println("客户端上线!");//1. 从控制台读取用户输入的内容.//2. 把请求发送给服务器//3. 从服务器读取响应.//4. 把响应显示到界面上.Scanner scanner = new Scanner(System.in);try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while(true) {//1. 从控制台读取用户输入的内容.System.out.println("-> ");String request = scanner.next();//2. 把请求发送给服务器PrintWriter writer = new PrintWriter(outputStream);//使用println是为了让请求后面带上 换行//是为了和服务器读取请求 scanner.next()呼应.writer.println(request);writer.flush();//3.  读取服务器返回的响应.Scanner scannerNetwork = new Scanner(inputStream);String response = scannerNetwork.next();//4. 把响应显示到界面上.System.out.println(response);}} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException {TcpEchoClient client = new TcpEchoClient("127.0.0.1",9090);client.start();}
}

上述代码存在两个问题:

1. 服务器程序会出现文件资源泄露的情况.
前面写过的DatagramSocket, ServerSocket 都没写 close,但没关系,因为DatagramSocket 和 ServerSocket, 都是在程序中,只有这么一个对象,生命周期贯穿整个程序的. 但 clientSocket则是在循环中,每次有一个新的客户端来建立连接,都会创建出新的 clientSocket .
如果有很多客户端都来建立连接,此时,就意味着每个连接都会创建 clientSocket. 如果没有手动 close此时这个 socket 对象会占据着文件描述符表的位置,一旦占满,文件资源就泄露了.
那要怎么办呢?

在这里插入图片描述
在这里插入图片描述

在 processConnection方法末尾加上下面的代码即可.

 finally {//手动关闭clientSocket,避免文件资源泄露.try {clientSocket.close();} catch (IOException e) {throw new RuntimeException(e);}}

既然文件资源泄露是因为clientSocket没关,那能不能在processConnection(clientSocket);执行完之后,再把clientSocket关闭呢?

public void start() throws IOException {System.out.println("服务器启动!");while(true) {//1. 通过accept方法,把内核中已经建立好的连接拿到应用程序.Socket clientSocket = serverSocket.accept();//2. 处理一个连接的逻辑.processConnection(clientSocket);clientSocket.close();}}

显然是不可以的,如果 在processConnection方法执行过程中遇到问题,抛出异常.那么还没执行到clientSocket.close();循环就结束了.
考虑到抛异常的问题, 于是就将代码改成try with source结构:

    public void start() throws IOException {System.out.println("服务器启动!");while(true) {//1. 通过accept方法,把内核中已经建立好的连接拿到应用程序.try(Socket clientSocket = serverSocket.accept()) {//2. 处理一个连接的逻辑.processConnection(clientSocket);}}}

2. 多个客户端无法同时与服务器进行交互.

先设置允许存在多个客户端.
在这里插入图片描述
同时运行两个客户端,在服务端上只能看到第一个客户端. 第二个客户端与服务器没有进行任何交互.

在这里插入图片描述
模拟两个客户端连接服务器的过程:
① 第一个客户端过来之后accept 就返回了,得到一个clientSocket.进入了 processConnection. 又进入了一个 while 循环, 这个循环中,就需要反复处理客户端发来的请求数据.如果客户端没发请求,服务器的代码
就会阻塞scanner.hasNext处.
② 此时此刻,第二个客户端也过来建立连接了, 连接是可以成功建立的. 建立成功之后,连接对象就会在内核的队列里等待代码通过 accept. 但是第二个客户端永远不可能执行accept方法,除非第一客户端断开连接.
怎么让两个客户端同时执行呢?

关键就是,让两个循环能够"并发"执行. 这就涉及到前面学过的多线程知识了.
创建新的线程,让新的线程去调用 processConnection
主线程就可以继续执行下一次 accept 了,新线程内部负责 processConnection的循环此时意味着,每次有一个客户端,就都得给分配一个新的线程, 又因为涉及到频繁创建销毁线程. 所以更好的方式是用线程池, 不用当然也可以, 用的话效率高一些.

解法Ⅰ 服务器引入多线程:

在这里插入图片描述

    public void start() throws IOException {System.out.println("服务器启动!");while(true) {//1. 通过accept方法,把内核中已经建立好的连接拿到应用程序.Socket clientSocket = serverSocket.accept();Thread t = new Thread(() -> {//2. 处理一个连接的逻辑.processConnection(clientSocket);});t.start();}}

解法Ⅱ 避免频繁创建销毁线程, 服务器引入线程池:

在这里插入图片描述

    //服务器引入线程池public void start() throws IOException {System.out.println("服务器");ExecutorService service = Executors.newCachedThreadPool();while(true) {//1. 通过accept方法,把内核中已经建立好的连接拿到应用程序.Socket clientSocket = serverSocket.accept();service.submit(new Runnable() {@Overridepublic void run() {processConnection(clientSocket);}});}}


本篇博客到这里就结束啦, 感谢观看 ❤❤❤

🐎期待与你的下一次相遇😊😊😊

相关文章:

【网络编程】从零开始彻底了解网络编程(三)

本篇博客给大家带来的是网络编程的知识点. 🐎文章专栏: JavaEE初阶 🚀若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅🚀 要开心要快乐顺便进步 TCP流…...

NVIDIA --- 端到端自动驾驶

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、传统驾驶模型二、NVIDIA的端到端驾驶模型1.基本模型2.自查讯向量3.通用框架 总结 前言 端到端自动驾驶指的是系统接收来自摄像头雷达和激光雷达的原始传感…...

关于在Springboot中设置时间格式问题

目录 1-设置全局时间格式1.Date类型的时间2.JDK8时间3.使Date类和JDK8时间类统统格式化时间 2-关于DateTimeFormat注解 1-设置全局时间格式 1.Date类型的时间 对于老项目来说,springboot中许多类使用的是Date类型的时间,没有用到LocalDateTime等JDK8时…...

CSRF请求伪造

该漏洞主要是关乎于用户,告诫用户不可乱点击链接,提升自我防范,才能不落入Hacker布置的陷阱! 1. cookie与session 简单理解一下两者作用 1.1. 🍪 Cookie:就像超市的会员卡 存储位置:你钱包里…...

(一)单机架构、应用数据分离架构、应用服务集群架构

文章目录 明确为什么要学习架构的演进单机架构什么是单机架构单机架构的模型单机架构的优缺点优点缺点 单机架构的技术案例 应用数据分离架构什么是应用数据分离架构架构模型应用数据分离架构的优缺点优点缺点 技术案例 应用服务集群架构什么是应用服务集群架构架构模型应用服务…...

Python数据分析案例72——基于股吧评论数据的情感分析和主题建模(LDA)

背景 好久没更新了,最近忙其他去了。最近股市波动太大,看了不少新闻的评论。抽空写了个股吧评论数据的LDA建模和情感分析,简单写到博客上来更新一下。 数据来源 上证指数(000001)股吧_上证指数怎么样_分析讨论社区— 数据来源上述网站的东…...

Git分支管理方案

成都众望智慧有限公司Git分支管理方案 采用 轻量级Git Flow 敏捷版本控制策略,在保证稳定性的同时提升开发效率。以下是优化后的方案: 1. 精简分支模型(相比6-8人团队减少分支层级) 分支类型作用生命周期devops生产环境代码&am…...

力扣-160.相交链表

题目描述 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整个链式结构中不存在环。 注意,函数返…...

c语言中float和double 类型的区别

在 C 语言里,float和double都用于表示浮点数,不过二者在多个方面存在差异,下面为你详细介绍: 1. 存储空间大小 在 C 语言中,数据类型所占用的存储空间大小通常与编译器和系统架构有关,但一般来说&#xf…...

【C++】特殊类的设计、单例模式以及Cpp类型转换

📚 博主的专栏 🐧 Linux | 🖥️ C | 📊 数据结构 | 💡C 算法 | 🅒 C 语言 | 🌐 计算机网络 上篇文章: C 智能指针使用,以及shared_ptr编写 下篇文章&#xff…...

050_基于springboot的音乐网站

一、系统架构 前端:vue | element-ui | html | jquery | css | ajax 后端:springboot | mybatis 环境:jdk1.8 | mysql | maven | nodejs | idea 二、代码及数据 三、功能介绍 01. web端-注册 02. web端-登录 03. web…...

全局变量Msg.sender

msg.sender 在 Solidity 中,有一些全局变量可以被所有函数调用。 其中一个就是 msg.sender,它指的是当前调用者(或智能合约)的 address。 注意:在 Solidity 中,功能执行始终需要从外部调用者开始。 一个合…...

【论文阅读】平滑量化:对大型语言模型进行准确高效的训练后量化

论文题目:SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models 论文地址:[2211.10438] SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models 代码地址:http…...

【资料推荐】LVDS Owner’s Manual

一份年代有些久远的技术资料,但是内容全面且经典! 本用户手册提供了很多有用的信息,首先简要概述了三种最常见的高速接口技术:LVDS(包括B-LVDS和M-LVDS)、CML和LVPECL,并对其相应的特性进行了分…...

ARM Cortex-M (STM32)如何调试HardFault

目录 步骤 1: 实现一个有效的 HardFault 处理程序 步骤 2: 复现 HardFault 并使用调试器分析 步骤 3: 解读故障信息 步骤 4: 定位并修复源代码 HardFault 是 ARM Cortex-M 处理器中的一种异常。当处理器遇到无法处理的错误,或者配置为处理特定类型错误&#xff…...

黑马 redis面试篇笔记

redis主从 version: "3.2"services:r1:image: rediscontainer_name: r1network_mode: "host"entrypoint: ["redis-server", "--port", "7001"]r2:image: rediscontainer_name: r2network_mode: "host"entrypoint:…...

Docker端口映射与容器间DNS发现:打通服务通信的任督二脉

Docker端口映射与容器间DNS发现:打通服务通信的任督二脉 一、端口映射深度解析1.1 端口映射核心机制映射规则语法: 1.2 高级映射技巧批量端口映射:查看端口绑定状态: 二、容器间服务发现机制2.1 自定义网络DNS体系DNS解析特性&…...

DBdriver使用taos数据库

首先创建连接 连接后比如数据库里有三个库 选择其中的hypon 选中localhost,右键sql编辑器,打开sql控制台 就插入了一条数据...

观成科技:摩诃草组织Spyder下载器流量特征分析

一、概述 自2023年以来,摩诃草组织频繁使用Spyder下载器下载远控木马,例如Remcos。观成安全研究团队对近几年的Spyder样本进行了深入研究,发现不同版本的样本在数据加密、流量模式等方面存在差异。基于此,我们对多个版本样本的通…...

AIGC实战之如何构建出更好的大模型RAG系统

一、RAG 系统核心架构解析 1. 检索模块深度优化 1.1 混合检索技术实现 技术原理:结合稀疏检索(BM25)与密集检索(DPR),通过动态权重分配提升检索精度。例如,在医疗领域,BM25 负责精…...

C++入门小馆: 深入了解STLlist

嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的pa…...

【Git】Fork和并请求

当你在 GitHub 或其他代码托管平台上 Fork 了一个项目后,你可以基于你的 Fork 进行开发,并通过 Pull Request(PR) 的方式将你的更改提交给原始项目(也称为上游仓库)。以下是完整的流程和步骤: 1…...

小白学习java第15天:JDBC

1.数据库驱动 想一下我们之前是怎么操作数据库,是不是使用SQL语句对其mysql数据库管理系统,然后管理系统在进行数据库(硬盘文件里面的)进行操作。那么我现在想使用应用程序对其数据库进行操作,应该怎么办呢&#xff1…...

大模型应用开发(PAFR)

Prompt问答 特征:利用大模型推理能力完成应用的核心功能 应用场景: 文本摘要分析 舆情分析 坐席检查 AI对话 AgentFunction Calling 特征:将应用端业务能力与AI大模型推理能力结合,简化复杂业务功能开发 应用场景: 旅行指南 数据…...

Go 剥离 HTML 标签的三把「瑞士军刀」——从正则到 Bluemonday

1 为什么要「剥皮」&#xff1f; 安全&#xff1a;去掉潜在的 <script onload…> 等恶意标签&#xff0c;防止存储型 XSS。可读性&#xff1a;日志、消息队列、搜索索引里往往只需要纯文本。一致性&#xff1a;不同富文本编辑器生成的 HTML 五花八门&#xff0c;统一成「…...

U-Mail邮件加速服务:全球链路加速,安全稳定收发

由于跨国网络拥堵、带宽不稳定等因素&#xff0c;导致海外用户在使用企业邮箱收发邮件时&#xff0c;经常出现邮件收发不畅的问题。针对这种情况&#xff0c;U-Mail正式推出了邮件加速服务&#xff0c;U-Mail邮件加速服务依托全球优质加速链路和转发集群服务器&#xff0c;为海…...

实战交易策略 篇十七:翻倍黑马交易策略

文章目录 系列文章设置指标判断大盘买入的条件判断大盘卖出的条件精选个股,挖掘明天能上涨的黑马熊市选股牛市选股短线最佳买点短线最佳卖点“翻倍”的核心秘籍系列文章 实战交易策略 篇一:奥利弗瓦莱士短线交易策略 实战交易策略 篇二:杰西利弗莫尔股票大作手操盘术策略 实…...

反爬策略应对指南:淘宝 API 商品数据采集的 IP 代理与请求伪装技术

一、引言​ 在电商数据驱动决策的时代&#xff0c;淘宝平台海量的商品数据极具价值。然而&#xff0c;淘宝为保障平台安全和用户体验&#xff0c;构建了严密的反爬体系。当采集淘宝 API 商品数据时&#xff0c;若不采取有效措施&#xff0c;频繁的请求极易触发反爬机制&#x…...

论文精读:大规模MIMO波束选择问题的量子计算解决方案

论文精读&#xff1a;大规模MIMO波束选择问题的量子计算解决方案 概要&#xff1a; 随着大规模多输入多输出系统&#xff08;MIMO&#xff09;在5G及未来通信技术中的应用&#xff0c;波束选择问题&#xff08;MBS&#xff09;成为提升系统性能的关键。传统的波束选择方法面临计…...

精益数据分析(13/126):洞察数据关系,灵活调整创业方向

精益数据分析&#xff08;13/126&#xff09;&#xff1a;洞察数据关系&#xff0c;灵活调整创业方向 大家好&#xff01;在创业和数据分析的探索之路上&#xff0c;每一次的学习都是成长的宝贵机会。今天&#xff0c;咱们接着深入学习《精益数据分析》&#xff0c;一起探索相…...