【JavaEE网络】深入理解Socket套接字及其在网络编程中的应用

目录

    • Socket套接字
      • UDP VS TCP
        • 有连接 VS 无连接
        • 可靠传输 VS 不可靠传输
        • 面向字节流 VS 面向数据报
      • 全双工 VS 半双工
    • UDP数据报套接字编程
      • DatagramSocket API
      • DatagramPacket API
      • InetSocketAddress API
      • UDP回显客户端服务器
      • 服务器和客户端的工作流程
      • UDP翻译客户端服务器


Socket套接字

概念

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

分类

Socket套接字主要针对传输层协议划分为如下三类:

  1. 流套接字:使用传输层TCP协议

TCP,即Transmission Control Protocol(传输控制协议),传输层协议。

以下为TCP的特点:

  1. 有连接
  2. 可靠传输
  3. 面向字节流
  4. 有接收缓冲区,也有发送缓冲区
  5. 大小不限

对于字节流来说,可以简单的理解为,传输数据是基于IO流,流式数据的特征就是在IO流没有关闭的情况下,是无边界的数据,可以多次发送,也可以分开多次接收。

  1. 数据报套接字:使用传输层UDP协议

UDP,即User Datagram Protocol(用户数据报协议),传输层协议。

以下为UDP的特点:

  1. 无连接
  2. 不可靠传输
  3. 面向数据报
  4. 有接收缓冲区,无发送缓冲区
  5. 大小受限:一次最多传输64k

对于数据报来说,可以简单的理解为,传输数据是一块一块的,发送一块数据假如100个字节,必须一次发送,接收也必须一次接收100个字节,而不能分100次,每次接收1个字节。

  1. 原始套接字:原始套接字用于自定义传输层协议,用于读写内核没有处理的IP协议数据。简单了解即可。

UDP VS TCP

具体的网络编程

写一个应用程序,让这个程序可以网络通信,这里就需要调用传输层的api

传输层提供协议主要是两个:

  1. UDP;
  2. TCP。

两套不同的api => socket api

UDP和TCP之间的主要特点对比:

  1. UDP:无连接,不可靠传输,面向数据报,全双工
  2. TCP:有连接,可靠传输,面向字节流,全双工
有连接 VS 无连接
  1. TCP进行编程的时候,也是存在类似的建立连接的过程(打电话:打过去对方接通才能说话)
  2. UDP:发微信/短信就是不需要建立连接就能进行通信的
  3. 这里所谓的“连接”是抽象的。客户端和服务器之间,使用内存保存对端的信息,双方都保存这个信息,此时“连接”就出现了。这里最大的区别是一个客户端可以连接多个服务器,一个服务器也可以对应多个客户端的连接(多对多)
可靠传输 VS 不可靠传输
  1. 可靠传输,不是说A给B发的消息100%能到(这个要求太难了),A尽可能把消息传给B,并且传输失败的时候,A能感知到;或者传输成功的时候,A也能感知到
  2. TCP可靠(传输效率更低),UDP不可靠(传输效率更高),但TCP比UDP更安全这句话是错误的

注意:谈到“网络安全”

指的是如果你传输的数据是否容易被黑客截获以及如果被截获后是否会泄露一些重要信息。安全和入侵,破解,加密反编译。

面向字节流 VS 面向数据报
  1. TCP和文件操作类似,都是“流”式的(由于这里传输的单位是字节,称为字节流)

接100ml水,可以一次接100ml,也可以一次接50ml分两次,也可以一次接10ml分十次

通过tcp读写100字节数据,可以一次读写100字节,也可以一次读写50字节分两次,也可以一次读写10字节分十次

  1. UDP是面向数据报,读写的基本单位,是一个UDP数据报(包含了一系列数据/属性)

全双工 VS 半双工

  1. 全双工:一个通道可以双向通信
  2. 半双工:一个通道只能单向通信

UDP数据报套接字编程

两个核心的类:DatagramSocketDatagramPacket

DatagramSocket API

DatagramSocket是一个socket对象,操作系统,使用文件这样的概念,来管理一些软硬件资源,网卡,操作系统也是使用文件的方式管理网卡的,表示网卡的这类文件,称为Socket文件。Java中的socket对象,就对应这系统里的socket文件(最终还是要落到网卡),要进行网络通信,必须得先有socket对象

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

DatagramSocket 构造方法:

方法签名方法说明
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端
DatagramSocket(int port)创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端

第一个构造方法用于客户端,使用哪个端口由系统自动分配

第二个构造方法用于服务端,使用哪个端口手动指定

关于“五元组”:源IP、源端口、目的IP、目的端口、协议类型

其中的源端口和目的端口,此时就需要给客户端、服务器各自分配端口号

客户端给服务器发数据:源端口就是客户端的端口,目的端口就是服务器的端口

服务器给客户端发数据:源端口就是服务器的端口,目的端口就是客户端的端口

IP地址:对于服务器来说,需要有一个固定的端口号,方便其他客户端找到;对于客户端来说,端口号不能指定固定值

一个客户端的主机,上面运行的程序很多,天知道你手动指定的端口是不是被别的程序占用了,让系统自动分配一个端口是更明智的选择。

服务器是完全在程序员手里控制的,程序员可以把服务器上的多个程序安排好,让他们使用不同的端口

DatagramSocket 方法:

方法签名方法说明
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacket p)从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

注意:receive这里传入的是个空对象,这是服务器先创建好放入的,然后一直阻塞等待着的,然后请求来了后再把数据解析放进去的

DatagramPacket API

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

DatagramPacket构造方法:

方法签名方法说明
DatagramPacket(byte[] buf, int length)构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度作为存储数据的空间(第二个参数length)
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号

DatagramPacket这个对象里就包含着通信双方的IP和Port

DatagramPacket方法:

方法签名方法说明
InetAddress getAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
byte[] getData()获取数据报中的数据(UDP数据报的载荷部分,即完整的应用层数据报

构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创建。

InetSocketAddress API

InetSocketAddressSocketAddress 的子类 )构造方法:

方法签名方法说明
InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号

一个服务器要给很多客户端提供服务,也不知道客户端什么时候来,只能“时刻准备着”,随时准备提供服务

服务器步骤

  1. 读取数据,并解析(固定套路)
  2. 根据请求,计算出响应(对于回显服务器不关心这个过程,请求是啥就返回啥响应。但商业级的服务器主要的代码都是在这一步)
  3. 把响应写回客户端(固定套路)

客户端步骤

  1. 从控制台读取用户输入内容
  2. 构造请求对象,并发给服务器
  3. 读取服务器的响应,并解析出响应内容
  4. 显示到屏幕上

UDP回显客户端服务器

服务器

//UDP回显服务器
//客户端法的请求是啥,服务器返回的相应就是啥
public class UdpEchoServer {
    private DatagramSocket socket = null;//socket对象

    //参数是服务器要绑定的端口(相当于我这个店开在哪里)
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);//这里如果new失败了,最典型的情况是,端口号被占用了
    }

    //启动服务器
    public void start() throws IOException {
        System.out.println("服务器启动");
        while (true) {
            //反复的,长期的执行针对客户端请求处理的逻辑
            //一个服务器看,运行过程中,要做的事情,主要是三个核心环节
            //1. 读取请求,并解析
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);//保存数据内存空间需要手动指定
            socket.receive(requestPacket);//传入时是个空对象,receive执行完后就填充完这个参数了
            //如果客户端的请求一直没来,receive方法就会一直阻塞等待,等到有客户端发起请求过来
            //这样的转字符串前提是,客户端发的数据就是一个文本的字符串
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
            //2. 根据请求,计算出响应。(回显服务器不关心这个过程,请求是啥就返回啥响应)
            String response = process(request);
            //3. 把相应写回给客户端
            //此时需要告诉网卡,要发的内容是啥,要发给谁
            //前两个参数是关于要发的内容是啥以及长度
            //最后一个参数是要发给谁
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            //记录日志
            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);//这个端口号是随便写的,服务器启动要固定绑定到9090
        server.start();
    }
}

//运行结果1
服务器启动
[/127.0.0.1:55735]req:你好,resp:你好//55735就是系统随机分配的端口号,req就是请求,resp就是响应
[/127.0.0.1:55735]req:hello,resp:hello
    
//运行结果2
服务器启动
[/127.0.0.1:64432]req:你好1,resp:你好1//64432这是第一个客户端的端口号
[/127.0.0.1:64433]req:你好2,resp:你好2//64433这是第二个客户端的端口号

客户端

//UDP的回显客户端
public class UdpEchoClient {
    private DatagramSocket socket=null;
    private String serverIp;//形如 127.0.0.1 字符串格式的IP
    private int serverPort;

    //参数是服务器的ip和服务器的端口
    public UdpEchoClient(String ip,int port) throws SocketException {
        serverIp=ip;
        serverPort=port;
        //这个new操作就不再指定端口了,让系统自动分配一个空闲窗口
        socket=new DatagramSocket();
    }

    //启动客户端,让客户端反复从控制台读取用户输入的内容,把这个内容构造成UDP请求,发给服务器,再读取服务器返回的UDP响应
    //最终显示在客户端屏幕上
    public void start() throws IOException {
        Scanner sc=new Scanner(System.in);
        System.out.println("客户端启动");
        while(true){
            //1.从控制台读取用户输入内容
            System.out.print("->");//命令提示符,提示用户输入字符串
            String request=sc.next();
            //2.构造请求对象,并发给服务器
            //前两个参数是关于要发的内容是啥以及长度
            DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(serverIp),serverPort);//发给哪个ip,哪个端口
            //上面需要的是InetAddress对象,通过InetAddress的静态方法getByName来将serverIp构造成InetAddress对象
            socket.send(requestPacket);
            //3.读取服务器的响应,并解析出响应内容
            DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            String response=new String(responsePacket.getData(),0,responsePacket.getLength());
            //4.显示到屏幕上
            System.out.println(response);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient client=new UdpEchoClient("127.0.0.1",9090);//服务器Ip是前者,端口号和服务器的是一样的
        //客户端接下来要访问9090这个端口
        client.start();
    }
}

//运行结果1
客户端启动
->你好//我客户端这边输入的请求
你好//服务器返回的响应
->hello//我客户端这边输入的请求
hello//服务器返回的响应
    
//运行结果2
客户端启动//这是第一个客户端
->你好1
你好1
客户端启动//这是第二个客户端
->你好2
你好2

注意:要先启动服务器再启动客户端

IDEA上启动多个程序要稍微设置一下

1.在这里插入图片描述

2.在这里插入图片描述

不这么设置就无法同时启动上面的两个客户端的情况

服务器和客户端的工作流程

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

后续任意服务器客户端的工作流程都是如此,只是计算响应中的process方法更加复杂

网络环境的现状,NAT机制是主流,在NAT机制下,把IP地址分为了外网IP和内网IP(内网IP不能直接访问),而“我的电脑”没有外网IP,获取外网IP的方法则是找到一个“有外网IP的电脑”即云服务器。

UDP翻译客户端服务器

注意:服务器部分继承了上面回显服务器的start(),客户端是一样的

//翻译服务器,继承了回显服务器,但要将process重写
public class UdpDictServer extends UdpEchoServer{//继承了UdpEchoServer回显服务器
    private Map<String,String> dict=new HashMap<>();
    public UdpDictServer(int port) throws SocketException {
        super(port);

        dict.put("cat","小猫");
        dict.put("dog","小狗");
        dict.put("fuck","我超");
        //可以在这里继续添加千千万万个单词,使每个单词都有对应的翻译
    }

    public static void main(String[] args) throws IOException {
        UdpDictServer server=new UdpDictServer(9090);
        //start不需要再写一遍了,直接复用UdpEchoServer的start
        server.start();
    }

    //是复用了之前的代码,但又要作出调整
    @Override
    public String process(String request){
        //把请求对应单词的翻译,给返回回去
        return dict.getOrDefault(request,"该词没有查询到");
    }
}

//运行结果

//服务器部分
服务器启动
[/127.0.0.1:53183]req:dog,resp:小狗
[/127.0.0.1:53183]req:cat,resp:小猫
[/127.0.0.1:53183]req:fuck,resp:我超
[/127.0.0.1:53183]req:aaa,resp:该词没有查询到
    
//客户端部分
客户端启动
->dog
小狗
->cat
小猫
->fuck
我超
->aaa
该词没有查询到

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

轻松找回误删文件,告别企业数据丢失,如何有效利用teamOS二级回收站,提升数据管理效率

在数字化时代&#xff0c;我们越来越依赖电子文件来记录和管理重要信息。 然而&#xff0c;伴随着这种便利的同时&#xff0c;误删或恶意操作导致的文件丢失也成为了一个令人头疼的问题。 那么本文就来谈一谈&#xff0c;企业网盘如何解决误删、甚至恶意删除的问题。 可道云…

高效的数据采集如何促进企业发展?

大数据开启了一个大规模生产、分享和应用数据的时代&#xff0c;它给技术和商业带来了巨大的变化。麦肯锡研究表明&#xff0c;在医疗、零售和制造业领域&#xff0c;大数据每年可以提高劳动生产率0.5-1个百分点。大数据在核心领域的渗透速度有目共睹&#xff0c;然而调查显示&…

ctfshow——XSS

文章目录 XSS介绍什么是xss&#xff1f;XSS危害XSS的分类常用XSSpayload web316——反射型XSSweb317——过滤<script> web318——过滤script、imgweb319——不止过滤script、imgweb320——过滤空格web321——不止过滤空格web322——不止过滤空格web323web324web 325web32…

ubuntu下安装python模块 pip intall xxx报错

报错内容大概如下&#xff1a; WARNING: Retrying (Retry(total4, connectNone, readNone, redirectNone, statusNone)) after connection broken by NewConnectionError(<pip._vendor.urllib3.connection.HTTPSConnection object at 0x7f0fc68d6370>: Failed to establ…

Python 基础、流程、容器、函数

一、基础语法 1.1 前言 1.1.1 Python简介 Python是一门编程语言&#xff0c;Python的作者是Guido van Rossum&#xff08;龟叔&#xff09; Python优点&#xff1a;简单易学 Python与嵌入式、集成电路行业 强大的库和工具生态系统&#xff1a;Python拥有广泛而强大的库和…

javaWeb项目-社区医院管理服务系统功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、Java技术 Java语…

什么是全局特征,什么又是局部特征

全局特征和局部特征是用来描述数据中信息的两种不同方式&#xff0c;特别是在图像处理、模式识别和机器学习领域中经常被提到。它们有助于理解和分析数据的不同层面&#xff1a; 全局特征&#xff08;Global Features&#xff09; 全局特征描述了整个数据集的整体属性。在图像…

布局香港之零售小店篇 | 香港一人小企与连锁超市的竞争

近年来&#xff0c;内地品牌入驻香港市场开拓业务已成大势所趋。香港特区政府早前公布的「2023年有香港境外母公司的驻港公司按年统计调查」显示&#xff0c;2023年母公司在海外及内地的驻港公司数量高达9039家。内地品牌在香港的成功落地&#xff0c;不仅为香港市民带来了丰富…

杰理695的UI模式LED灯控制

UI模式LED灯修改每个模式对应的LED灯闪烁修改在ui_normal_status_deal(u8 *status, u8 *power_status, u8 ui_mg_para)

质量精美的UI设计素材库:3000+图标设计资源免费下载!

作为一名设计师&#xff0c;你的设计灵感来自哪里&#xff1f;想象一下吗&#xff1f;事实上&#xff0c;材料库仍然是大多数设计师必不可少的东西&#xff0c;如果你能更方便地找到他们可用的设计材料&#xff0c;那么在创作中&#xff0c;无疑可以用一半的努力得到两倍的结果…

【技巧】Git 版本控制工具没有图标提示怎么办?

Git 版本控制工具在日常开发中使用率是非常高的&#xff0c;多数情况下会安装 TortoiseGit 之类的插件&#xff0c;让文件夹显示图标&#xff0c;方便观察文件的状态。但是有时装完插件之后发现&#xff0c;文件夹/文件并没有图标显示&#xff0c;可以按照以下思路进行排查&…

TCP三次握手详解

目录 什么是TCP TCP头格式组成 三次握手 第一次握手 第二次握手 第三次握手 三次握手的好处 为什么需要三次握手&#xff1f; 什么是TCP 传输控制协议(TCP)是Internet一个重要的传输层协议。TCP提供面向连接、可靠、有序、字节流传输服务。 面向连接&#xff1a; 应用…

AI时代的GPU集群网络算力分析

浅谈GPU集群网络、集群规模和集群算力 引言在生成式AI&#xff08;GenAI&#xff09;和大模型时代&#xff0c;不仅需要关注单个GPU卡的算力&#xff0c;更要关注GPU集群的总有效算力。单个GPU卡的有效算力可以通过该卡的峰值算力来测算&#xff0c;例如&#xff0c;对于Nvidia…

力扣HOT100 - 98. 验证二叉搜索树

解题思路&#xff1a; class Solution {public boolean isValidBST(TreeNode root) {return recur(root,Long.MIN_VALUE,Long.MAX_VALUE);}public boolean recur(TreeNode root,long lower,long upper){if(rootnull) return true;if(root.val<lower||root.val>upper) re…

Linux系统-服务器硬件及RAID配置

目录 一.服务器 1.服务器与普通计算机的区别 2.功能 3.分类&#xff08;按照产品形态分&#xff09; 4.架构&#xff08;按照指令集类型&#xff09; 5.相关指令 5.1.查看服务器CPU的信息 5.2.查看服务器内存的信息 二.RAID磁盘阵列&#xff08;Redundant Array …

C++ 二叉搜索树

文章目录 二叉搜索树的概念二叉搜索树的性质二叉搜索树的模拟实现封装框架添加操作查找操作删除操作 二叉搜索树的概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都…

编程基础“四大件”

基础四大件包括&#xff1a;数据结构和算法,计算机网络,操作系统,设计模式 这跟学什么编程语言,后续从事什么编程方向均无关&#xff0c;只要做编程开发&#xff0c;这四个计算机基础就无法避开。可以这么说&#xff0c;这基础四大件真的比编程语言重要&#xff01;&#xff0…

【打工日常】云原生之使用Docker部署开源云笔记工具Leanote

一、Leanote蚂蚁笔记介绍 1.Leanote简介 Leanote 蚂蚁笔记是一款国产开源的私有云笔记工具。它支持普通格式笔记、Markdown语法、专业数学公式编辑、和思维导图&#xff0c;并且支持vim&emacs等编辑模式。 2.Leanote功能 拥有Markdown 语法支持、无干扰写作模式、Vim和Ema…

2024年深圳杯东三省数学建模联赛A题论文首发第二种思路

深圳杯A题论文代码分享资料链接&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1L2NVgoefSW-yuqZjEB3wcw 提取码&#xff1a;sxjm 问题一 数据转换&#xff1a; 首先&#xff0c;我们将监测站的经纬度坐标转换为基于米的笛卡尔坐标系。这是因为在地面上的大尺度距离…

【设计模式】使用中介者模式优化表单交互

我们想象一下机场的指挥塔&#xff0c;如果没有指挥塔的存在&#xff0c;每一架飞机要和方圆 100 公里内的所有飞机通信&#xff0c;才能确定航线以及飞行状况&#xff0c;后果是不可想象的。现实中的情况是&#xff0c;每架飞机都只需要和指挥塔通信。指挥塔作为调停者&#x…
最新文章