【网络原理】网络编程Socket套接字基础知识汇总

news2024/9/20 14:46:33

目录

1.网络初始:

2.网络编程:

3.UDP数据报套接字:

4.TCP流套接字:


1.网络初始:

  1. 局域网(LAN)广域网(WAN)
  2. IP地址用于定位主机的网络地址。端口号可以标识主机中发送数据接收数据的进程(用于定位主机中的进程)。一个端口只能被一个进程绑定(通常情况),但是一个进程可以绑定多个端口号。
  3. 协议是俩个人的事情,只有双方都了解并且遵守才有意义!
  4. 协议分层,上层协议调用下层协议,下层协议给上层协议提供服务,相邻的层是可以相互交互的,但是不能跨层级。
  5. TCP/IP五层网络模型和封装,
    假设主机A给主机B发了个helloworld
    主机A发送的过程
    
    一.应用层
       应用程序会把输入的helloworld构造成约定好的应用层协议的报文
       应用程序就会把这个应用数据报文,交给传输层协议
       传输层是操作系统内核实现的,操作系统提供了一些API给应用程序,
       这些API叫做socket api,代码调用这些api就可以把应用层的数据交给传输层(交给了操作系统内核)
    
    二.传输层
       传输层这里有很多协议,最典型的就是TCP协议,此处以TCP为例
       TCP协议要在之前的基础上,加上个TCP的协议报头
       这个TCP报头里面最重要的就是源端口和目的端口!
       传输层继续将这个数据交给网络层进行处理
            
    三.网络层
       网络层中最典型的就是IP协议
       IP协议把整个TCP数据看成整体,作为载荷部分,在前头加上IP协议报头
       IP协议报头里面有很多信息,最关键的就是源IP和目的IP
       构造好IP数据报之后,IP协议继续把整个数据交给数据链路层
            
    四.数据链路层
       数据链路层的协议有很多,最典型的就是以太网
       以太网这个歌协议既管数据链路层,又管物理层
       以太网数据帧将IP数据报的前头加上帧头(源mac地址和目的mac地址),后头加上帧尾(校验和)
    
    五.物理层
       到达物理层的数据已经组织好了
       就可以通过物理层设备(网卡)把上述数据的二进制bit流转换成光信号或电信号来传输
  6. 分用就是封装的逆过程,封装是打包快递,而分用就是拆开快递。
  7. 网络中的细节太多了,如果一个协议搞定,那这个协议就会非常的复杂。因此就需要拆分,拆分的多了,又要分层。拆分之后,一个协议负责一件事情,这样才把这些关键信息放到了不同的协议报头中。

2.网络编程:

  1. 网络编程指的是网络上的主机,通过不同的进程,以编程的方式实现网络通信网络编程主要是针对应用层。
  2. 网络编程套接字,就是研究如何写代码完成网络编程。socket api是一切网络编程的基础。
  3. socket套接字是操作系统给应用程序提供的API,描述的是应用层和传输层的交互其实socket api就是传输层给应用层提供的
  4. API就是一组类和方法。应用程序就可以通过socket api来进行网络编程(操作网卡)。
  5. 网络传输层中又很多种协议,最主要的就是TCP和UDP。因此操作系统就提供了俩个不同的版本的API。
  6. 传输层中TCP和UDP的区别
    TCPUDP
    有连接无连接
    可靠传输不可靠传输
    面向字节流面向数据报
    全双工全双工
  7. TCP和文件操作一样是基于“流”的,而UDP则是以“数据报”为基本单位。全双工是一个通道,双向通信;半双工是一个通道,单向通信。网络通信一般都是全双工的。有连接就相当于打电话,必须通信的双方建立好了连接才可以正常打电话;而无连接相当于发短信,直接就可以发送过去。

3.UDP数据报套接字:

  1. DatagramSocketDatagramPacket是UDP socket需要掌握的类。
  2. DatagramSocket,是网卡的代言人,借助这个类来读写网卡。通过网卡发送数据就是写文件,接收数据就是读文件。
    方法签名说明
    DatagramSocket()一般用于客户端,创建一个UDP数据报套接字的socket,绑定到随机一个端口
    DatagramSocket(int port)一般用于服务器,创建一个UDP数据报套接字的socket,绑定到指定端口
    void receive(DatagramPacket p )接收数据报,没有收到会阻塞等待
    void send(DatagramPacket p )发送数据报,不会阻塞等待
    void close()关闭数据报套接字
  3. socket本质上是一个文件。socket对应到网卡这个硬件设备,操作系统也是把网卡当作文件来管理。通过网卡发送数据,就是写文件;通过网卡接收数据,就是读文件。
  4. DatagramPacket,代表一个UDP数据包,是一次发送/接受的基本单位;发送和接收的是DatagramPacket。
    方法签名说明
    DatagramPacket(byte[ ] b,int length)构造一个DatagramPacket用来接收数据报,接收的数据保存在字节数组里
    DatagramPacket(byte[ ] b,int offset,int length,address)构造一个DatagramPacket用来发送数据报,发送的数据为字节数组的指定长度。address为指定目的主机的IP和端口号
    getAddress()从接收的数据报中获取发送端主机IP地址;或从发送的数据报中获取接收端主机IP地址
    int getPort()从接收的数据报中获取发送端主机端口号;或从发送的数据报中获取接收端主机端口号
    byte[ ] getData()获取数据报中的数据
  5. UDP实现回显服务器(服务器部分)
    //UDP版本:回显服务器的服务器部分
    
    public class UdpEchoServer {
        private DatagramSocket socket = null;
    
        //参数的端口表示服务器要绑定的端口
        //不需要指定IP,就是本机的IP
        public UdpEchoServer(int port) throws SocketException {
            socket = new DatagramSocket(port);
        }
    
        //启动服务器
        public void start() throws IOException {
            System.out.println("服务器启动了!!!");
            while(true){
                //1.读取请求并且解析
                //socket的receive操作需要一个空的requestPacket,receive方法的参数是一个输出型参数
                //将空的DatagramPacket对象交给receive,在receive里面负责把从网卡读到的数据填充到这个对象中
                DatagramPacket requestPacket = new DatagramPacket(new byte[1024],1024);//要给DatagramPacket申请内存空间
                socket.receive(requestPacket);
                //将DatagramPacket转换成字符串    getData()是获取数据报中的数据,返回一个byte[]
                String request = new String(requestPacket.getData(),0, requestPacket.getLength());
    
                //2.根据请求计算响应
                String response = process(request);
    
                //3.把响应返回给客户端
                //发送DatagramPacket对象需要指定IP地址和端口号
                DatagramPacket responsePacket = new DatagramPacket(    //getSocketAddress就是得到客户端的IP和端口号
                        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(1025);
            server.start();
        }
    }

  6. UDP实现回显服务器(客户端部分)
    //UDP版本:回显服务器的客户端部分
    
    public class UdpEchoClient {
        private DatagramSocket socket = null;
        private String serverIP;
        private int serverPort;
        //服务器的IP一般不用写,就是本机的IP
        //需要传服务器的IP和服务器的端口
        public UdpEchoClient(String serverIp,int serverPort) throws SocketException {
            socket = new DatagramSocket();//不用指定参数
            this.serverIP = serverIp;
            this.serverPort = serverPort;
        }
    
        public void start() throws IOException {
            Scanner scanner = new Scanner(System.in);
            while(true){
                //1.从控制台上读取用户输入的内容
                System.out.print("-> ");
                String request = scanner.nextLine();
    
                //2.构造一个UDP请求,发送给服务器
                DatagramPacket requestPacket = new DatagramPacket(
                        //request.getBytes().length这里的length单位是字节
                        //request.length()这里的length()单位是字符,不可以改成这样
                        request.getBytes(),request.getBytes().length, InetAddress.getByName(this.serverIP),this.serverPort);
                socket.send(requestPacket);
    
                //3.从服务器接收响应,并且转成字符串
                DatagramPacket responsePacket = new DatagramPacket(new byte[1024],1024);
                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 {
            //IP是某某食堂,端口号是某某窗口
            UdpEchoClient client = new UdpEchoClient("127.0.0.1",1025);
            client.start();
        }
    }
    

  7. DatagramPacket的三种构造方法
  8. 为什么服务器需要指定端口,而客户端不用指定端口???答:服务器指定端口目的就是方便客户端找到服务器在哪而客户端不指定端口因为操作系统会分配一个空闲的端口,如果手动指定了万一用户电脑上的其他程序占用了这个端口,就会导致程序无法正确运行了。
  9. 对于服务器来说,读取请求并且解析根据请求计算响应把响应写回到客户端执行的速度是极快的。如果有多个客户端同时发来请求,服务器也是可以响应的,但是本质上这三个请求的串行处理的!
  10. 当前俩个程序放在同一个主机上是通过127.0.0.1这个IP来通信的;也可以把俩个程序放在不同的主机上也是可以通信的,但是如果放在不同的主机上,要确保服务器的地址是可以访问到的!

4.TCP流套接字:

  1. ServerSocketSocket是TCP流套接字需要掌握的俩个类。
  2. ServerSocket是创建TCP服务器的api,给服务器使用的类,用来监听端口
    方法签名说明
    ServerSocket(int port)创建一个服务端流套接字Socket,并且绑定指定端口
    Socket accept()有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接否则阻塞等待
    void close()关闭此套接字
  3. Socket既会给服务器使用也会给客户端使用,用来传输数据。
    方法签名说明
    Socket(String host,int port)创建一个客户端流套接字Socket,并且尝试和对应IP的主机上对应端口的进程建立连接
    InetAddress getInetAddress()返回套接字所连接的地址,获取IP和端口
    int getPort()返回套接字所连接的端口
    InputStream  getInputStream()返回此套接字的输入流
    OutputStream getOutputStream()返回此套接字的输出流
  4. TCP实现回显服务器(服务器部分)
    //TCP版本:回显服务器服务器部分
    
    public class TcpEchoServer {
        private ServerSocket listenSocket = null;
    
        public TcpEchoServer(int port) throws IOException {
            listenSocket = new ServerSocket(port);
        }
    
        public void start() throws IOException {
            System.out.println("服务器启动!!");
            //使用线程池
            ExecutorService service = Executors.newCachedThreadPool();
            while(true) {
                //1.先调用accept
                Socket clientSocket = listenSocket.accept();
    
    
                //2.再来处理这个连接,这里应该使用多线程,每个客户端连上来都分配一个新的线程负责处理
                //使用多线程确实可以解决问题,但是会频繁的创建和销毁线程!
    //            Thread t = new Thread(()->{
    //                try {
    //                    processConnection(clientSocket);
    //                } catch (IOException e) {
    //                    throw new RuntimeException(e);
    //                }
    //            });
    //            t.start();
    
                service.submit(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            processConnection(clientSocket);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }
    
        private void processConnection(Socket clientSocket) throws IOException {
            System.out.printf("[%s:%d] 客户端上线!\n",
                    clientSocket.getInetAddress().toString(),clientSocket.getPort());
    
            //处理客户端的请求
            //clientSocket代表的是服务器的网卡,inputStream代表从网卡读数据也就相当于从客户端读取数据
            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] 客户端下线!\n",
                                clientSocket.getInetAddress().toString(),clientSocket.getPort());
                        break;
                    }
                    String request = scanner.next();
    
                    //2.根据请求计算响应
                    String response = process(request);
    
                    //3.把响应写回到客户端
                    PrintWriter printWriter = new PrintWriter(outputStream);
                    printWriter.println(response);
                    //刷新缓冲区确保数据确实是通过网卡发送出去了
                    printWriter.flush();
    
                    System.out.printf("[%s:%d] req: %s; resp: %s\n",
                            clientSocket.getInetAddress().toString(),clientSocket.getPort(),request,response);
                }
    
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                //为什么这个clientSocket要关闭文件,前面的listenSocket和UDP程序中的socket都不需要关闭文件呢?
                clientSocket.close();
            }
        }
        public String process(String request) {
            return request;
        }
    
        public static void main(String[] args) throws IOException {
            TcpEchoServer server = new TcpEchoServer(9090);
            server.start();
        }
    }

  5. TCP实现回显服务器(客户端部分)
    //TCP版本:回显服务器客户端部分
    
    public class TcpEchoClient {
        private Socket socket = null;
    
        public TcpEchoClient(String serverIp, int serverPort) throws IOException {
            socket = new Socket(serverIp, serverPort);
        }
    
        public void start() {
            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();
    
                    //2.发送请求给服务器
                    PrintWriter printWriter = new PrintWriter(outputStream);
                    printWriter.println(request);
                    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 {
            TcpEchoClient server = new TcpEchoClient("127.0.0.1",9090);
            server.start();
        }
    
    }

  6. TCP实现回显服务器的服务器代码部分,如果使用1的话,就不能让多个客户端同时使用服务器;如果使用2,频繁的创建和销毁代价较大,所以推荐使用线程池!
  7. TCP实现回显服务器的服务器代码中需要close文件!
  8. 启动服务器,如果没有客户端建立连接,服务器就会阻塞等待。如果有一个客户端过来了,此时就会显示客户端已上线并且向下执行代码。如果再有一个客户端也过来了,使用上述的方案1那么不会显示这个客户端已上线
  9. TCP中的长短连接。TCP发送数据时需要先建立连接,什么时候关闭连接就决定是短连接还是长连接。短连接:每次收到数据并返回响应后,都关闭连接,也就是短连接只能一次收发数据,TCP每个连接只处理一个客户端请求能够保证快速调用到accept。长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,也就是长连接可以多次收发数据,TCP建立连接之后,要处理客户端的多次请求才导致无法快速调用accept。


如果对您有帮助的话,

不要忘记点赞+关注哦,蟹蟹

如果对您有帮助的话,

不要忘记点赞+关注哦,蟹蟹

如果对您有帮助的话,

不要忘记点赞+关注哦,蟹蟹

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构六:堆

前言:上一篇我们讲了二叉树,你知道吗?堆的底层是一棵完全二叉树。这样说会不会就会觉得熟悉了。 目录 1.堆的概念及存储方式 2:堆的创建 2.1:向下调整 3.堆的插入和删除 3.1:堆的插入 3.2:堆的删除 …

基于Web的商城后台管理系统的设计与实现

🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…

Oracle和MySQL查询所有的表信息和字段信息

Oracle和MySQL查询所有的表信息和字段信息1. MySQL1.1 查询表1.2 查询字段1.2.1 方式1->SHOW FULL COLUMNS1.2.2 方式2->information_schema.COLUMNS1.3 查表和字段1.4 查表和字段-->转程Oracle需要的数据类型2. Oracle2.1 查表和字段的单表查询2.2 整理查表和字段的s…

超详细的JUnit单元测试介绍

前言 本文为JUnit单元测试相关知识,下边将对JUnit单元测试概念,JUnit优点,JUnit安装与使用,JUnit运行流程与常用注解,JUnit测试套件使用及参数化设置,JUnit断言等进行详尽介绍~ 📌博主主页&…

大数据Hadoop之——Apache Hudi 与 Presto/Trino集成

文章目录一、概述二、Trino 环境部署1)安装JDK2)安装python3)安装Trino1、下载解压并配置环境变量2、修改配置3、启动服务4、测试验证三、在Hive中创建表关联Hudi表1)添加jar包2)创建库表关联Hudi四、Hudi 与 Trino集成…

SpringCloud Alibaba系列 Sentinel(三)

高并发下的微服务容错方案? 限流、熔断、降级 1:限流 在高并发系统中一定要用,高并发的所有请求进来,不是让每个请求都打到后台集群的,后台集群有它的消费能力,应该在它消费能力之内放行请求,…

Hadoop HA集群全是standBy解决办法

文章目录原理解决方案原理 hadoop集群配置HA后,会存在多个namenode,但是同一时间仅有一台NN为Active的状态,其他NN都是StandBy的状态。 上图是hadoop集群配置HA的原理图,从上图我们可以看到多个NN的状态切换,是依靠Z…

linux命令与makefile学习

linux命令与makefile学习文件权限通配符*常用命令makefilegcc与g区别:Linux上有一句话:一切皆文件 普通文件 “-” 目录文件 “d” (directory) 管道文件 “p” (piping) 链接文件“l” (li…

SAP FICO银行账户余额查询表开发说明书(包括开发源代码、测试样例及FS)

程序说明 满足财务银行账户余额查询明细的需求; 支持财务实时查看银行余额数据。 筛选界面 序号 栏位标题 字段类型 是否必须 是否为范围

【pwn】2022 祥云杯 部分wp

【pwn】2022 祥云杯 部分wp 前言 又是一年的祥云杯,相比去年我啥也不会写,今年起码写了几个签到… 又被队友带飞咯 protool Google的Protobuf,参考学习连接 https://bbs.pediy.com/thread-270004.htm 发现了栈溢出,protobuf…

Unity技术手册-UGUI零基础详细教程-Toggle切换

往期文章分享点击跳转>《导航贴》- Unity手册,系统实战学习点击跳转>《导航贴》- Android手册,重温移动开发 本文约3千字,新手阅读需要7分钟,复习需要2分钟 【收藏随时查阅不再迷路】 👉关于作者 众所周知&#…

2.6 Python 基本数据类型

1. 数据类型 类型是变量所指的内存中对象的类型. 内置的type()函数可以用来查询变量所指的对象类型。Python 3中有六个标准的数据类型: Numbers(数字), String(字符串), List(列表), Tuple(元组), Sets(集合), Dictionary(字典).2. Numbers 数字型 Python 有三种数字类型 in…

SpringMVC基本配置

小常规 springmvc的处理器对应的bean必须按照规范格式开发,为避免加入无效的bean可通过bean加载过滤器进行包含设定或排除设定,表现层bean标注通常设定为Controller在此发现图片没有加载出来回到程序去分析当发起一个请求以后DispatcherServlet配置拦截所…

【JVM技术专题】 深入分析class字节码指令方法调用详解「原理篇」

方法调用详解 ​ 调用目标在程序代码写好、编译器进行编译时就必须确定下来,这类方法的调用称为解析。 解析 ​ 在Java语言中符合**“编译期可知,运行期不可变”**这个要求的方法,主要包括静态方法和私有方法两大类,前者与类型…

【JavaScript】网页轮播图

目录HTML搭建功能实现小圆圈事件左右按钮事件自动播放轮播图也叫焦点图,是网页中比较常见的网页特效。功能:鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。点击右侧按钮一次,图片往左播放一张,以此类…

UACANet: Uncertainty Augmented Context Attention for Polyp Segmentation代码补充

上一篇看了文章创新点的代码,现在看一下train文件等其余的文件。 看主函数: import os import torch import argparse import tqdm import sysimport cv2 import torch.nn as nn import torch.distributed as distfrom torch.optim import Adam, SGD fr…

CVE-2022-21907 Microsoft Windows HTTP 协议栈远程代码执行漏洞复现

目录 0x01 声明: 0x02 简介: 0x03 漏洞概述: 0x04 影响版本: 0x05 环境搭建: 下载: 开启IIS: 0x06 漏洞复现: 利用POC: 0x07 流量分析: 客户端&am…

算法提升 (三)基础数据结构

作者:小萌新 专栏:算法提升 作者简介:大二学生 希望能够和大家一起进步! 内容简介:简单介绍基本数据结构的简单面试题 不负韶华 链表 阅读这篇文章之前需要有初阶数据结构的基础 关于链表的结构如果还有不了解的同学…

智能AI创意图片编辑Luminar Neo

Luminar Neo是Mac上的智能AI技术编辑软件背景替换、图像层、除尘、重新照明选项等,从而实现精确掌控。同时在这款软件中还拥有可简化复杂的编辑程序,如此一来用户即可将自己大脑中想象的愿景变为现实,让使用者能有多大胆的想法都可以在这款软…

深度学习 卷积神经网络原理

深度学习 卷积神经网络原理一、前言二、全连接层的局限性三、卷积层3.1 如何进行卷积运算?3.2 偏置3.3 填充3.4 步长3.5 卷积运算是如何保留图片特征的?3.6 三维卷积3.7 多种特征提取四、池化层五、全连接层六、参考资料一、前言 本文分析了全连接层存在…