【Java EE初阶十二】网络编程TCP/IP协议(一)

 1. 网络编程

        通过网络,让两个主机之间能够进行通信->就这样的通信来完成一定的功能,进行网络编程的时候,需要操作系统给咱们提供一组API,通过这些API来完成编程;API可以认为是应用层和传输层之间交互的路径,其中Socket Api(可以认为是插座)通过这个一套Socket Api可以完成不同主机之间,不同系统之间的网络通信;   

        传输层提供的网络协议主要有两个tcp、udp:这两个协议的特性(工作原理差异很大,就会导致使用这两种协议进行网络编程,也会存在一定的差异)

1.1 TCP和UDP的区别

        1、TCP是有连接的,UDP是无连接的;

        这里的连接是抽象的概念,计算机中,这种抽象的连接是很常见的,此处的连接本质上就是建立连接的双方,各自保存对方的信息,即两台计算机建立连接,就是双方彼此保存了对方的关键信息;

        TCP想要通信,就需要先建立连接(即计算机保存对方的信息),做完之后,才能后续通信(如果A和B想要建立连接,但是B拒绝了,通信就无法完成建立)

        UDP想要通信,就直接发送数据报即可,不需要征得对方的同意,UDP自身也不会保存对方的信息(虽然UDP不知道,但是写程序的人得知道,UDP自己不保存对方的信息,但是调用UDP的socket api的时候就要把对方的位置信息等都传输过去)

        2、TCP是可靠传输的,UDP是不可靠传输的;

        网络上进行的通信,A->B发送一个信息,首先送到B的信息不可能做到100%送达,

所谓的可靠传输,就是退而求其次,当A->B发送一个消息,但是消息是不是达到B这一方,A这边自己是能感知到的,所以A在消息发送失败的时候就可以采取一定的措施(尝试重传之类的措施)

        TCP就内置了可靠的传输机制,但是UDP就没有内置可靠传输;

        可靠传输的不足:1、可靠传输所使用的机制更加复杂;2、可靠传输会导致消息的传输效率更加低;

        综上所述:

        TCP协议:发送方知道传输的数据是否成功的传输给接收方

        UDP协议:消息发出去,就不管了,不再考虑消息是否成功发送给接收方;

        3、TCP是面向字节流的,UDP是面向数据报的

        TCP也是和文件操作一样,以字节为单位来进行传输;UDP则是按照数据报(UDP有着自己严格的数据报格式)为单位来进行传输的

        4、TCP和UDP都是全双工的;

        一个信道,允许双向通信,就是全双工;一个信道,只能单向通信,就是半双工;

代码中使用一个socket对象,就可以发送数据也可以接收数据;

2. 关于UDP

2.1 UDP的socket api

        Socket其实是操作系统中的一个概念,本质上是一种特殊的文件;Socket就属于是把“网卡”这个设备给抽象成了文件了,往Socket文件里面写数据,就相当于通过网卡发送数据,从Socket文件里面读数据,就相当于通过网卡接收数据,(如此把网络通信和文件操作给统一了)

        DatagramSocket :

       Java中,就是用DatagramSocket这个类,来表示系统内部的socket文件;

        DatagramPacket: 使用这个类,来表示一个UDP数据报;UDP是面向数据报的,每一次传输都是以UDP数据报为基本单位的;

 2.2 基于UDP实现通信

        写一个简单的UDP的客户端/服务器通信的程序

        要求我们写的程序没有具体的业务逻辑,只是调用单纯的socket api,让客户端给服务器发送一个请求,且该请求是一个从控制台输入的字符串,服务器收到字符串之后,就会把这个字符串原封不动的返回给客户端,客户端在显示出来(即该服务器是回显服务器echo server)

1、读取请求并解析

        服务器和客户端都需要创建socket对象,但是服务器的socket一般要显示的指定一个端口号,而客户端的socket一般不能显式指定(不显式指定,此时系统就会自动分配一个随机的端口),客户端的端口号是不需要确定的,交给系统进行随机分配即可,如果我们手动指定确定的端口,就可以和别人的程序的端口号冲突;

Q:服务器这边手动指定端口号,难道就不会出现端口号冲突吗?为啥客户端在意这个冲突,而服务器不在意这个冲突?

A:首先服务器是在程序员手里面的,一个服务器上有哪些程序,这些程序都使用哪些端口,程序员都是可控的,且程序员在写代码的时候,就可以指定一个空闲的端口,给当前的服务器使用即可;其次客户端的情况就不一样了,因为客户端是在用户的电脑上的,一方面,用户有成千上万,每一个用户电脑上所装的程序都不一样,占用的短端口也不一样,林外一方面,用户这边如果出现了端口号冲突,用户这方面自己本身不知道是什么原因

        所以,客户端的端口号还是交给系统来进行分配,因为系统能保证肯定分配一个空闲的端口号;

        服务器一旦启动,就会立即执行到这里的receive这里的方法,此时客户端的请求可能还没有过来,此时遇到这种情况,receive就会直接阻塞,一直阻塞到客户端把请求发送过来为止;

2、根据请求计算响应(一般的服务器都会经历的过程)

        这个步骤是一个服务器程序最核心的步骤,我们当先的echo server不涉及到这些流程,只要求当请求过来就把请求当作响应,因为UDP是无连接的,所以udp自身不会保存数据要发送的对象信息,就需要每一次发送的时候,重新指定数据要发送到哪儿去;

 

3、把响应显示到客户端

4、打印一个日志,将我们进行的数据交互都打印出来

Q:为啥上述所写的代码中,没有写close,因为socket也是文件,不关闭的话就会出现之前我们所讲的文件资源泄露问题嘛?

A:        首先socket是文件描述符表中的一个表项,每一次打开一个文件,就会占用一个位置;文件描述符是在pcb上的(跟随的是进程)

        其次这个socket在整个程序的运行中都是需要使用的(不能提前关闭),当socket不需要使用的时候,意味着程序就要结束了,进程结束,此时随之的文件描述符表就会销毁了(pcb也会销毁),被销毁后资源就会被系统进行自动回收;

        最后,所谓出现泄露,是指代码中频繁打开文件,但是不会关闭,在一个进程的运行过程中,不断的打开文件,并逐渐消耗掉文件描述符表里面的内容,最终该资源就会被消耗殆尽了;但是,如果进程的生命周期很短,打开一下没多久就关闭了,谈不上所谓的资源泄露;

       综上所述,文件资源泄露这样的问题,在服务器这边是比较严重的,在客户端这边其实影响不大;

2.3 代码实现

2.3.1 服务器代码

package network;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class UdpEchoServer {// 创建一个 DatagramSocket 对象. 后续操作网卡的基础.private DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {// 这么写就是手动指定端口socket = new DatagramSocket(port);// 这么写就是让系统自动分配端口// socket = new DatagramSocket();}public void start() throws IOException {// 通过这个方法来启动服务器.System.out.println("服务器启动!");// 一个服务器程序中, 经常能看到 while true 这样的代码.while (true) {// 1. 读取请求并解析.DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);socket.receive(requestPacket);// 当前完成 receive 之后, 数据是以 二进制 的形式存储到 DatagramPacket 中了.// 要想能够把这里的数据给显示出来, 还需要把这个二进制数据给转成字符串.String request = new String(requestPacket.getData(), 0, requestPacket.getLength());// 2. 根据请求计算响应(一般的服务器都会经历的过程)//    由于此处是回显服务器, 请求是啥样, 响应就是啥样.String response = process(request);// 3. 把响应写回到客户端.//    搞一个响应对象, DatagramPacket//    往 DatagramPacket 里构造刚才的数据, 再通过 send 返回.DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);// 4. 打印一个日志, 把这次数据交互的详情打印出来.System.out.printf("[%s:%d] req=%s, resp=%s\n", requestPacket.getAddress().toString(),requestPacket.getPort(), request, response);}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer server = new UdpEchoServer(9090);server.start();}
}

2.3.2 客户端代码

package network;import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class UdpEchoClient {private DatagramSocket socket = null;private String serverIp = "";private int serverPort = 0;public UdpEchoClient(String ip, int port) throws SocketException {// 创建这个对象, 不能手动指定端口.socket = new DatagramSocket();// 由于 UDP 自身不会持有对端的信息. 就需要在应用程序里, 把对端的情况给记录下来.// 这里咱们主要记录对端的 ip 和 端口 .serverIp = ip;serverPort = port;}public void start() throws IOException {System.out.println("客户端启动!");Scanner scanner = new Scanner(System.in);while (true) {// 1. 从控制台读取数据, 作为请求System.out.print("-> ");String request = scanner.next();// 2. 把请求内容构造成 DatagramPacket 对象, 发给服务器.DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,InetAddress.getByName(serverIp), serverPort);socket.send(requestPacket);// 3. 尝试读取服务器返回的响应了.DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);// 4. 把响应, 转换成字符串, 并显示出来.String response = new String(responsePacket.getData(), 0, responsePacket.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {//UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);UdpEchoClient client = new UdpEchoClient("42.192.83.143", 9090);client.start();}
}

2.3.3 客户端和服务器交互逻辑

         分析如下:

1、服务期先启动,启动之后就开始进行循环,执行到receive这里并阻塞(此时还没有客户端过来)

2、客户端开始启动,也会先进入while循环,执行scanner.next,并且在这里进行阻塞,当用户在控制台输入字符串后,next就会返回,并且构造请求数据病发出来

3、客户端发出数据之后:

        服务器:就会从rfeceive中返回,进一步的执行解析请求为字符串,执行process操作,执行send操作

        客户端:继续往下执行,执行到receive服务器的响应;

4、客户端收到从服务器返回的数据之后,就会从receive中返回,执行这里的打印操作,也就把响应给显示出来了;

5、服务器这边完成过一次循环之后,又执行到receive这里;客户端这边完成一次循环之后,又执行到scanner.next这里,双双进入阻塞;

ps:本篇内容主要讲解关于UDP时间简单通信的过程,如果大家感兴趣的话就请一键三连哦!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/465120.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CTFshow-WEB入门-信息搜集

web1(查看注释1) wp 右键查看源代码即可找到flag web2(查看注释2) wp 【CtrlU】快捷键查看源代码即可找到flag web3(抓包与重发包) wp 抓包后重新发包,在响应包中找到flag web4(robo…

面试经典150题——三数之和

​"The road to success and the road to failure are almost exactly the same." - Colin R. Davis 1. 题目描述 2. 题目分析与解析 2.1 思路一——暴力方法 因为三个数相加为0,那么说明其中两个加数的和与另一个加数为相反数则满足题意。所以可以得到…

CSP-201912-1-报数

CSP-201912-1-报数 知识点总结 整数转化为字符串#include <string> string str_num to_string(num);字符串中查找是否包含字符‘7’&#xff1a;str_num.find(7) 未找到返回-1找到返回返回该字符在字符串中的位置&#xff08;即第一次出现的索引位置&#xff09; #i…

Netty应用(六) 之 异步 Channel

目录 12.Netty异步的相关概念 12.1 异步编程的概念 12.2 方式1&#xff1a;主线程阻塞&#xff0c;等待异步线程完成调用&#xff0c;然后主线程发起请求IO 12.3 方式2&#xff1a;主线程注册异步线程&#xff0c;异步线程去回调发起请求IO 12.4 细节注释 12.5 异步的好处…

【MySQL基础】:深入探索DQL数据库查询语言的精髓(上)

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; MySQL从入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. DQL1.1 基本语法1.2 基础查询1.3 条件查询1.3 聚合函数 &#x1f324;️ 全篇…

【开源】基于JAVA+Vue+SpringBoot的实验室耗材管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 耗材档案模块2.2 耗材入库模块2.3 耗材出库模块2.4 耗材申请模块2.5 耗材审核模块 三、系统展示四、核心代码4.1 查询耗材品类4.2 查询资产出库清单4.3 资产出库4.4 查询入库单4.5 资产入库 五、免责说明 一、摘要 1.1…

【JavaScript 漫游】【014】正则表达式通关

文章简介 JS 语言中的 RegExp 对象提供正则表达式的功能。本篇文章旨在对该对象的相关知识点进行总结。内容包括&#xff1a; 正则表达式概述RegExp 对象的实例属性RegExp 对象的实例方法字符串与正则表达式相关的实例方法正则表达式匹配规则 概述 正则表达式的概念 正则表…

口腔助手|口腔挂号预约小程序|基于微信小程序的口腔门诊预约系统的设计与实现(源码+数据库+文档)

口腔小程序目录 目录 基于微信小程序的口腔门诊预约系统的设计与实现 一、前言 二、系统功能设计 三、系统实现 1、小程序前台界面实现 2、后台管理员模块实现 四、数据库设计 1、实体ER图 2、具体的表设计如下所示&#xff1a; 五、核心代码 六、论文参考 七、最新…

树莓派4B(Raspberry Pi 4B)使用docker搭建阿里巴巴sentinel服务

树莓派4B&#xff08;Raspberry Pi 4B&#xff09;使用docker搭建阿里巴巴sentinel服务 由于国内访问不了docker hub&#xff0c;而国内镜像仓库又没有适配树莓派ARM架构的sentinel镜像&#xff0c;所以我们只能退而求其次——自己动手构建镜像。本文基于Ubuntu&#xff0c;Jav…

python学习23

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

Pandas数据预处理之数据标准化-提升机器学习模型性能的关键步骤【第64篇—python:数据预处理】

文章目录 Pandas数据预处理之数据标准化&#xff1a;提升机器学习模型性能的关键步骤1. 数据标准化的重要性2. 使用Pandas进行数据标准化2.1 导入必要的库2.2 读取数据2.3 数据标准化 3. 代码解析4. 进一步优化4.1 最小-最大缩放4.2 自定义标准化方法 5. 处理缺失值和异常值5.1…

ubuntu中尝试安装ros2

首先&#xff0c;ubuntu打开后有个机器人栏目&#xff0c;打开后&#xff0c;有好多可选的&#xff0c;看了半天 ,好像是博客&#xff0c;算了&#xff0c;没啥关系&#xff0c;再看看其他菜单 这些都不是下载链接。先不管&#xff0c;考虑了一下&#xff0c;问了ai&#xff…