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

【EE初阶 - 网络原理】Socket 套接字

文章目录

  • 1. Socket 套接字
    • 1.1 概念
    • 1.2 分类
    • 1.3 套接字通信模型
      • 1.3.1 Java数据报套接字通信模型
      • 1.3.2 Java流套接字通信模型
    • 1.4 Scoket编程注意事项
  • 2. UDP数据报套接字编程
    • 2.1 API的介绍
      • 概念
      • 构造方法
      • 方法
      • 2.1.2 DatagramPacket
      • 2.1.3 InetSocketAddress ( SocketAddress的子类 )
    • 2.2 实现回显服务器
      • 2.2.1 实现原理
      • 2.2.2 代码实现
        • UDP Echo Server
        • UDP Echo Client

1. Socket 套接字

1.1 概念

Socket套接字,是由系统提供用于网络通信的技术,是基于TC/IP协议的网络通信的基本操作单元.基于Socket套接字的网络程序开发就是网络编程

1.2 分类

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

1.3 套接字通信模型

1.3.1 Java数据报套接字通信模型

  • 对于UDP协议来说,具有无连接,面向数据报的特征,即每次都是没有建立连接,并且一次发送全部数据报,一次接收全部的数据报
  • Java中使用UDP协议通信,主要是基于DatagramSocket类来创建数据报套接字,并使用DatagramSocket作为发送或接收的UDP数据报

对于一次发送及接收UDP数据报的流程如下:
在这里插入图片描述
以上只是一次发送端的UDP数据报发送,及接收端的数据报接收,并没有返回数据,也就是只有请求,没有响应

对于一个服务端来说,重要的是提供多个客户端的请求处理并相应,流程如下:
在这里插入图片描述

1.3.2 Java流套接字通信模型

在这里插入图片描述

1.4 Scoket编程注意事项

在这里插入图片描述

  • 1.客户端和服务端:开发时,经常是基于一个主机开启两个进程作为客户端和服务端,但真实的场景,一般都是不同主机;
  • 2.注意目的 IP 和目的端口号,标识了一次数据传输时要发送数据的终点主机和进程;
  • 3.Socket 编程我们是使用流套接字和数据报套接字,基于传输层的 TCP 或 UDP 协议,但应用层协议,也需要考虑,这块我们在后续来说明如何设计应用层协议。
  • 4.关于端口被占用的问题
  • 5.如果一个进程 A 已经绑定了一个端口,再启动一个进程 B 绑定该端口,就会报错,这种情况也叫端被占用。对于 java 进程来说,端口被占用的常见报错信息如下:

在这里插入图片描述
此时需要检查进程B绑定的是哪个端口,在查看该端口被哪个进程占用

通过端口号查进程的方式:

  • 在 cmd 输入 netstat - ano | findstr 端口号,则可以显示对应进程的pid,以下 命令显示了 8888 进程的pid
    在这里插入图片描述
  • 在任务管理器中,通过PID 查找进程
    在这里插入图片描述

解决端口被占用的问题:

  • 如果占用端口的进程A不需要运行,就可以关闭A后再启动需要绑定该端口的进程B
  • 如果需要运行A进程,则可以修改进程B的绑定端口,换为其他没有使用的端口

2. UDP数据报套接字编程

2.1 API的介绍

概念

计算机中的文件,通常是一个广义的概念,文件IO特指的是硬盘上的文件,是狭义的文件,除此之外,文件还可以代指一些硬件设备
Socket在计算机编程汇总,也可以认为是一种特殊的文件,打开socket文件,也会在文件描述表中分配一个表项,来表示这个文件
在这里插入图片描述
这样的文件特指网卡这样的硬件设备
对于网卡这样的硬件设备,在操作系统终究被抽象成socket文件,这样的设定,主要是为了方便操作网卡
直接操作网卡,需要往网卡的寄存器上写一些特定的数据,不好操作;操作系统管理一些硬件设备,是抽象成文件统一管理的;把操作网卡,转化成操作Socket文件,此时 Socket 文件,就相当于网卡的 “遥控器" ;
所以 DategramSocket ,就是一个用来表示网卡的文件,通过 DategramSocket 来操作网卡,只是加了一个 Dategram 前缀,意思就是基于UDP协议进行网络通信

DatagramSocket 是UDP Socket,用于发送和接收UDP数据报。

构造方法

在这里插入图片描述

方法

在这里插入图片描述
**DatagramSocket 类的 receive() & sand() 的参数类型,都是 DatagramPacket **

一个UDP数据包,就通过 DatagramPacket 对象来进行体现的,在进行receive() 或者 send(),都是按照 DatagramPacket 这样的数据包为定位进行接收的;

2.1.2 DatagramPacket

定义

DatagramPacket 是UDP Socket发送和接收的数据报

构造方法

UDP 数据包的载荷数据,可以通过构造方法来指定

在这里插入图片描述
方法

在这里插入图片描述
构造UDP发送的数据报时,需要传入SocketAddress,该对象可以使用InetSocketAddress 来创建

2.1.3 InetSocketAddress ( SocketAddress的子类 )

构造方法
在这里插入图片描述

2.2 实现回显服务器

2.2.1 实现原理

  • 客户端给服务器发一个数据的操作,称为请求
  • 服务器返回一个数据的操作,称为响应

在这里插入图片描述

  • 一个真实的服务器,请求和响应一般是不一样的,但是为了展示上述 API 的用法,就先不去管服务器中其他复杂的逻辑,写一个最简单的回显服务器(请求是什么,响应就是什么)

2.2.2 代码实现

UDP Echo Server

(1) 构造一个 socket 对象代表网卡文件

  • 输出 socket 文件内容,等于从网卡中读取数据;
  • 输入 socket 文件内容,等于向网卡内发送数据
    在这里插入图片描述

(2) 实现启动服务器的 start()

对于服务器来说,客户端啥时候发请求,发多少个请求,我们无法预测
因此服务器中通常都需要有一个死循环,持续不断的尝试读取客户端的请求数据~~
在这里插入图片描述
在住循环中,要实现的逻辑:
1.读取请求并解析
2.根据请求,计算相应(服务器最关键的逻辑),但我们这里写的是回显服务器,这个环节相当于省略了
3.把相应返回给客户端
每次每执行一次,就相当于处理了一次请求,处理请求的过程,典型的服务器也说上面这三个步骤

(3) 读取请求

服务器调用 receive() 对客户端发送的请求进行读取,等 receive() 方法执行完毕,参数里面对象的数据就是读取的结果:
在这里插入图片描述

创建一个 DatagramPacket 对象,用于接收请求

  • 创建 DatagramSocket 对象的时候,需要指定一个字节数组,并且传入接收的指定长度

在这里插入图片描述

  • DatagramPacket 表示个UDP数据报。此处传入的字节数组,就保存 UDP的载荷部分

读取网卡中的数据包

  • 把 DatagramPacket 对象(对象为全0)传给 receive()

在这里插入图片描述

  • receive() 就会在方法内部把从响应数据报中读到的数据,填充到 requestPacket 这个引用指向的对象中
  • receive() 执行完毕,参数里面的对象数据,就是需要从网卡中读取的数据(请求)

这个过程就相当于我们在食堂打饭,把空的盘子(requestPacket )交给打饭阿姨( receive() ),阿姨会把打好饭(读到的数据)的盘子还给我们

(4) 解析请求

  • 当前 UDP 载荷,是 DatagramSocket 对象的字节数组,存放着读取到的数据
  • 这些读取到的数据是二进制数据,为了方便后续处理,我们把读取到的二进制数据转换成字符串形式
    在这里插入图片描述
  • 通过字节数组构造一个 String 对象,是构造 String 对象的一个典型做法
    在这里插入图片描述
  • 上述操作,表示拿到了一个数据报中的字节数组,把整个字节数组传给String对象,并且指定字节数组有效部分的范围,调用相应的构造方法,构成一个字符串
    在这里插入图片描述

(5) 根据请求计算响应

  • 这是服务器最关键的逻辑,但是此处写的是回显服务器,这个环节就相当于省略了
    在这里插入图片描述
  • 根据解析数据报,得到的请求 request,计算出响应 response 的操作,封装成一个方法,可以起到解耦合的作用
  • 后续要写别的服务器,只需要修改 process() 的内容即可

(6) 把计算好的响应返回给客户端

  • 如何根据响应 response 构造 DatagramSocket 对象呢?
    在这里插入图片描述
  • 首先,需要拿出对响应数据报进行解析操作时,创建的字符串 request 里面的字节数组
    在这里插入图片描述
  • 要传入字节数组的长度,而不是使用字符串的长度,因为字符串的单位是字符,而我们要使用字节的个数,来作为当前 responsePacket 数据包的参数
    在这里插入图片描述

(7) 指定目的IP&目的端口

  • 发送的响应数据报 responsePacket 是没有明确标注有发送的目的IP&目的端口的,要想正确地返回响应,就必须给响应数据报显式地标注目的IP & 目的端口
  • 对于服务器返回响应的目的IP&目的端口,就是接到客户端请求的源IP&源端口
    在这里插入图片描述
  • 所以,通过调用 DatagramSocket 类中的 getSocketAddress(),该方法返回一个 InerSocketAddress 对象

InetSocketAddress(SocketAddress的子类)

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

  • 这个对象包含了目标IP 和 目标端口号 (都在报头中,而不是在载荷中)
  • 将这个对象作为参数,传给DatagramPacket对象,调用对应的构造方法

在这里插入图片描述

  • 所以,将getSocketAddress()方法返回的对象,作为参数来调用对应的构造方法,实例出的responsePacket,就会显式地标注响应数据报的目标IP 和 目标端口

在这里插入图片描述
(8) 发送响应给客户端

  • 服务器需要调send()方法,把创建好的响应数据报作为响应,返回给客户端
    在这里插入图片描述
  • send()的构造方法
    在这里插入图片描述
  • 所以,我们把刚刚构建好的响应数据报返回给客户端
    在这里插入图片描述

(9) 打印日志来记录客户端/服务器交互的过程
在这里插入图片描述

(10) 判断当前 socket 对象(文件)是否需要关闭

  • 文件是否需要关闭,考虑的是这个文件对象的生命周期是怎样的,此处的 socket 对象会自始至终伴随整个UDP服务器;
  • 只要服务器运行,就随时可能会从客户端中读数据,如果提前关闭 socket对象,那么UDP服务器继续运行也没有意义,所以socket对象,不能在服务器运行的过程中关闭;
  • 服务器关闭(进程结束),也不需要手动调用close(),因为进程结束时就会自动释放 PCB 的文件描述符表中的所有资源,
  • 所以当前socket文件不手动调用 close(),也是完全没问题的,因为socket的生命周期本来就需要跟随整个进程的;
  • 如果是有请求级别的文件对象,给一个请求,创建一个对象,就需要确保处理完毕之前,关闭对象。
  • 所以需要结合实际情况来确认一个对象的生命周期,通过生命周期,来决定对象是否应该关闭;

(11) 补充

在这里插入图片描述

  • DatagramPacket这个类型说是一个UDP数据报,其实也包含了一些源信息
    这个类有接受IP和端口号的属性,在通过receive() 缇娜充好DatagramPacket对象后,可以直接从对象中提取出UDP数据报的来源(源IP和源端口)
    所以在将DatagramPacket这个UDP数据包,作为 receive() 方法的输入型参数时,不只是把UDP中的数据读进去了,还把IP&端口号等信息也读进去了
UDP Echo Client
import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class UdpEchoClient {private DatagramSocket socket = null;// UDP 本身不保存对端的信息, 就自己的代码中保存一下private String serverIp;private int serverPort;// 和服务器不同, 此处的构造方法是要指定访问的服务器的地址.public UdpEchoClient(String serverIp, int serverPort) throws SocketException {this.serverIp = serverIp;this.serverPort = serverPort;socket = new DatagramSocket();}public void start() throws IOException {Scanner scanner = new Scanner(System.in);while (true) {// 1. 从控制台读取用户输入的内容.System.out.println("请输入要发送的内容:");if (!scanner.hasNext()) {break;}String request = scanner.next();// 2. 把请求发送给服务器, 需要构造 DatagramPacket 对象.//    构造过程中, 不光要构造载荷, 还要设置服务器的 IP 和端口号DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,InetAddress.getByName(serverIp), serverPort);// 3. 发送数据报socket.send(requestPacket);// 4. 接收服务器的响应DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);// 5. 从服务器读取的数据进行解析, 打印出来.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);client.start();}
}
http://www.dtcms.com/a/407797.html

相关文章:

  • 2025 9月25 最近两周的问题
  • golang做网站企业年金办法
  • 南京网站建设王道下拉??智能网站建设报价
  • 网站建设色系搭配企业简介介绍
  • 国内做网站的公司有哪些如何在局域网中做网站
  • wordpress仿站教程WordPress拍卖模板
  • app开发和网站开发的区别做同行的旅游网站
  • 做网站网站赚怎么买到精准客户的电话
  • 操作系统进程同步与互斥核心知识点复习
  • 网站推广方案中网站图片模板
  • 网站建设好处网络营销渠道
  • 网页模板免费资源整站优化包年
  • 网站图片动态换名一对一专属定制方案
  • 网站建设销售实习建筑网官网查证
  • Express路由设计最佳实践
  • 如何成为一名合格的Java架构师
  • 亚马逊seo是什么意思seo策略分析
  • 网站优化年报告seo整站优化费用
  • 【系统分析师】2025年上半年真题:综合知识-答案及详解(回忆版)
  • 0、计算机硬件 —— 主板
  • 做网站需要的流程东莞网站关键词优化收费
  • 基于 OpenCV Eigenfaces 的人脸识别实战与原理解析
  • 网站开发工程师职责wordpress post 插件
  • 预处理 讲解
  • Redis持久化:RDB和AOF
  • 盛泽做网站的怎么做自己下单的网站
  • Java 大视界 -- Java 大数据在智能公交调度优化与准点率提升中的应用实践(416)
  • dw做网站字体 别人电脑显示怎么用phpcmf做网站
  • 如何用ad做网站免费游戏大全
  • 简简单单搭建一个oss服务