• 网络编程基础(一):OSI 、TCP/IP协议与hello socket:用java实现第一个TCP连接


    通过了解OSI和TCP/IP协议,为后续网络编程提供一些理论基础

    网络层次
     

    一. OSI:7层网络层次

    OSI模型把网络分为7层,分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。

    遵循以下原则:

    1. 每一层使用下层提供的服务,并为上层提供服务。
    2. 不同节点的同等层按照协议实现对等层之间的通信

    1. 网络层次有哪些

    网络层次描述
    物理层
    物理层为上一层 提供物理连接,以及规定通信节点之间的机械和电气等特性,如规定电缆和接头的类型、传送信号的电压等。
    在这一层上,数据作为原始的比特(bit)流被传输。
    数据链路层
    1. 数据链路层要负责建立、维持和释放数据链路的连接。并负责 两个相邻结点无差错地传送以帧为单位的数据,每一帧包括一定数量的数据和一些必要的控制信息。
    2. 在传送数据时,如果接收方检测到所传数据中有差错,就要通知发送方重发这一帧。
    3. 本层的典型设备是交换机(Switch)。
    网络层
    1. 网络层将数据链路层提供的帧组成数据包。包中封装有网络层包头,包头中含有逻辑地址信息——源主机和目标主机的网络地址。
    2. 数据链路层负责 数据链路上的数据传输。从主机A到主机B的整个路径被称为路由, 网络层负责选择合适的路由
    3. 本层的典型设备是路由器(Router)。
    如图,主机A发送的数据先后经过节点1和节点4,最后到达主机B。 相邻两个节点之间的线路被称为数据链路,比如主机A与节点1、节点1与节点4,以及节点4与主机B之间的线路。数据链路层负责 数据链路上的数据传输。从主机A到主机B的整个路径被称为路由, 网络层负责选择合适的路由在这里插入图片描述
    传输层
    1. 为两个端系统(也就是源主机和目标主机)的会话层提供建立、维护和取消传输连接的功能,以可靠方式或者不可靠方式传输数据。
    2. 在这一层,信息的传送单位是报文。
    会话层
    1. 会话层管理 进程之间的会话过程,即负责建立、管理、终止进程之间的会话。
    2. 在这一层,信息的传送单位是报文。
    表示层
    对上层数据进行转换,以保证一个主机的应用层的数据可以被另一个主机的应用层理解。
    表示层的数据转换包括对数据的加密、解密、压缩、解压和格式转换等。
    应用层
    应用层确定进程之间通信的 实际用途。浏览Web站点、收发E-mail、上传或下载文件以及远程登入服务器等都可以看作是进程之间通信的实际用途。

    结点:指任何拥有唯一网络地址的设备,你比如说网站、网络传真机、网络打印机、档案服务器等。

     

    2. 数据传输在网络层次中的体现

    发送数据

    当源主机向目标主机发送数据时,在源主机方,数据先由上层向下层传递,每一层都会给上一层传递来的数据加上一个信息头(header),然后向下层发出,最后通过物理介质传输到目标主机。

    接收数据

    在目标主机方,数据再由下层向上层传递,每一层都先对数据进行处理,把信息头去掉,再向上层传输,最后到达最上层,就会还原成实际的数据。

    在这里插入图片描述

    网络的各个层次都有相应的协议,以下归纳了OSI常用层的一些典型协议,这些协议均由第三方提供。

    ·网络层协议:IP、IPX、ICMP、IGMP、AppleTalk DDP等。
    ·传输层协议:TCP、UDP、SPX等。
    ·表示层协议:ASCII、GIF、JPEG、MPEG等。
    ·应用层协议:TELNET、FTP、HTTP、SNMP、SMTP等。
    
    • 1
    • 2
    • 3
    • 4

     
     

    二. 4层网络模型:TCP/IP模型

    1. TCP/IP模型网络层次

    TCP/IP参考模型分为4个层次:应用层、传输层、网络层和网络接口层。
    每一层都有相应的协议:

    应用层协议:TELNET、FTP、HTTP、DNS、SNMP等。
    传输层协议:TCP
    网络层协议:IP
    网络接口层协议:以太网、令牌环网
    
    • 1
    • 2
    • 3
    • 4
    层次说明
    网络接口层
    1. 要求第三方实现为上层提供一个访问接口,使得上层能够传递IP数据包。
    网络层
    1. 功能是把IP数据包发送到目标主机。
    2. 为了尽快地发送数据,把原始数据分为多个数据包,然后沿不同的路径同时传递。
    3. 数据包到达的先后顺序和发送的先后顺序可能不同,这就需要上层——传输层对数据包重新排序,还原为原始数据.
    4. 协议采用的是IP(Internet Protocol),它规定了数据包的格式,并且规定了为数据包寻找路由的流程。
    传输层
    1. 功能是使源主机和目标主机上的进程可以进行会话
    2. 提供了两种连接协议:TCP(传输控制协议)、UDP(用户数据报)协议。
    3. TCP是面向连接、可靠的协议:
    发送端负责将上层传递的数据分解为报文段并传递给下层;
    接收端:将收到的报文重组后递交给上层;
    其次TCP还处理端到端的流量控制
    4. UDP是一个不可靠、无连接协议,主要适用于不需要对报文进行排序和流量控制的场合。
    应用层
    1. TCP/IP将OSI中的会话层和表示层合并到应用层实现。
    2. 基于TCP的应用层协议包含:FTP、HTTP/HTTPS、POP3、SMTP
    3. 基于UDP的应用层协议:DNS、SNMP

     
     

    2. IP协议

    2.1. IP地址

    IP网络(即在网络层采用IP的网)中的每台主机都有唯一的IP地址,IP地址用于标识网络中的每个主机。IP地址分为IPv4和IPv6。

    IP地址由两部分组成:IP网址和IP主机地址。IP网址表示网络的地址,IP主机地址表示网络中主机的地址

    网络掩码(通过和IP地址的与操作)用来确定IP地址中网址和主机地址。

     
    IP地址192.166.3.4的网址为192.166.3.0。如果把网络掩码设为255.255.0.0,那么IP网址为192.166.0.0。

     

    2.2. IP协议发送数据包的过程

    IP是面向包的协议,即数据被分成若干小数据包,然后分别传输它们。

    IP网络上的主机只能直接向本地网上的其他主机(也就是具有相同IP网址的主机)发送数据包。

    主机A向同一个网络上的另一个主机B发包时,会通过地址解析协议(Address Resolution Protocol,ARP)获得对方的物理地址,然后把包发给对方。

    ARP的运行机制为主机A在网络上广播一个ARP消息:“要寻找地址为192.166.3.5的主机”,接着,具有这个IP地址的主机B就会做出响应,把自身的物理地址告诉主机A。

     

    2.3. 域名 和 DNS

    域名和IP地址一一对应,通过使用域名,方便用户使用。

    域名是从右至左来表述其意义的,最右边的部分为顶层域,最左边的则是这台主机的机器名称。

    域名一般可表示为:主机机器名.单位名.网络名.顶层域名。
    如:mail.xyz.edu.cn,这里的mail是xyz学校的一个主机的机器名,xyz代表一个学校的名字,edu代表中国教育科研网,cn代表中国,顶层域一般是网络机构或所在国家地区的名称缩写。

    DNS(Domain Name System)协议采用DNS服务器提供把域名转换为IP地址的服务。

    DNS服务器分布在网络的各个地方,它们存放了域名与IP地址的映射信息。
     
    用户需要访问网络上某个主机时,只需提供主机直观的域名,DNS协议首先请求地理位置比较近的DNS服务器进行域名到IP地址的转换,如果在该服务器中不存在此域名信息,那么DNS协议再让远方的DNS服务器提供服务

     

    2.4. URL(统一资源定位器)

    专为标识网络上资源位置而设的一种编址方式,URL一般由3部分组成:

     应用层协议://主机IP地址或域名/资源所在路径/文件名
    
    • 1
    1. 例如JDK安装软件包的URL为:https://www.javathinker.net/software/jdk8.exe (点击即可下载)

    其中“http”指超文本传输协议,“www.javathinker.net”是Web服务器的域名,“software”是文件所在路径,“jdk8.exe”才是相应的文件。

    1. 在URL中,常见的应用层协议还包括ftp和file等,file协议用于访问本地计算机上的文件,使用这种协议的URL以“file:///”开头。
      在这里插入图片描述
       

    3. TCP以及端口

    IP在发送数据包的途中会遇到各种状况,例如可能路由器突然崩溃,使数据包丢失。
    再例如可能前面的数据包沿低速链路移动,而后面的数据包沿高速链路移动而超过前面的包,最后使得数据包的顺序混乱。
     
    对于TCP来说,TCP跟踪数据包顺序,并且在数据包顺序混乱时按正确顺序对其进行重组。如果数据包丢失,则TCP会请求源主机重新发送。

     

    3.1.通过TCP传输数据到进程

    IP发送数据:
    当主机A上的进程A1向主机B上的进程B1发送数据时,IP根据主机B的IP地址,把进程A1发送的数据送达主机B。

    TCP连接:
    TCP需要决定把数据发送到主机B中的哪个进程。TCP采用端口来区分进程。
    当两个进程进行一次通信时,就意味着建立了一个TCP连接,TCP连接的两个端点用端口来标识。

     

    3.2 端口号

    端口号的范围为0到65535,其中0到1023的端口号一般被固定分配给一些服务,从1024到65535的端口号供用户自定义的服务使用。

    比如21端口被分配给FTP服务,25端口被分配给SMTP(简单邮件传输)服务,80端口被分配给HTTP(超级文本传输)服务,135端口被分配给RPC(远程过程调用)服务等等。

    TCP连接与端口动态分配

    客户进程的端口一般由所在主机的操作系统动态分配,当客户进程要求与一个服务器进程进行TCP连接时,操作系统会为客户进程随机地分配一个还未被占用的端口,当客户进程与服务器进程断开连接时,这个端口就被释放。

     

    4. client/server通讯模式

    TCP/UDP推动了客户/服务器通信模式的广泛运用。

    在通信的两个进程中,一个进程为客户进程,另一个进程为服务器进程。客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求。

    通常,一个服务器进程会同时为多个客户进程服务,图中服务器进程B1同时为客户进程A1、A2和B2提供服务。
    在这里插入图片描述
     
     

    三、通过套接字编写client/server程序

    传输层向应用层提供了套接字Socket接口,Socket封装了下层的数据传输细节,应用层的程序通过Socket来建立与远程主机的TCP连接以及进行数据传输

    接下来我们Socket来实现TCP的连接!

    用java实现TCP连接

    在Java中,有3种套接字类:java.net.Socket、java.net.ServerSocket和DatagramSocket。
    其中Socket和ServerSocket类建立在TCP基础上,DatagramSocket类建立在UDP基础上。
    Java网络程序都采用客户/服务通信模式。

     

    server端

    package com.gao.socket.basic;
    
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
     * @Description 基于TCP协议的Socket通信,实现用户登录,服务端
     * @Author lianggao
     * @Date 2022/6/21 下午4:26
     */
    public class HelloServerSocket {
        public static void main(String[] args) throws IOException {
    
            /**
             * 1。 创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
             */
            //1024-65535的某个端口
            ServerSocket serverSocket = new ServerSocket(10086);
            //2、调用accept()方法开始监听,等待客户端的连接
            Socket socket = serverSocket.accept();
    
            /**
             * 3. 获取输入流 读取客户端信息
             */
            InputStream is = socket.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String info = null;
            while ((info = br.readLine()) != null) {
                System.out.println("我是服务器,客户端说:" + info);
            }
            //消费客户端消息之后关闭输入流
            socket.shutdownInput();
    
    
            /**
             * 4.服务端响应客户端请求
             */
            OutputStream os = socket.getOutputStream();
            PrintWriter pw = new PrintWriter(os);
            pw.write("欢迎您!");
            pw.flush();
    
    
            //5。 关闭资源
            pw.close();
            os.close();
            br.close();
            isr.close();
            is.close();
            socket.close();
            serverSocket.close();
        }
    }
    //我是服务器,客户端说:用户名:admin;密码:123
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    client端

    package com.gao.socket.basic;
    
    import java.io.*;
    import java.net.Socket;
    
    /**
     * @Description 创建客户端Socket,指定服务器地址和端口
     * @Author lianggao
     * @Date 2022/6/21 下午4:42
     */
    public class HelloClientSocket {
        public static void main(String[] args) throws IOException {
            /**
             * 1、创建客户端Socket,指定服务器地址和端口
             */
            Socket socket = new Socket("localhost", 10086);
    
            /**
             *2、向服务器端发送信息
             */
            OutputStream os = socket.getOutputStream();
            PrintWriter pw = new PrintWriter(os);  //将输出流包装成打印流
            pw.write("用户名:admin;密码:123");
            pw.flush();
            socket.shutdownOutput();
    
            /**
             * 3、 读取服务器端的响应信息
             */
            InputStream is = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String info = null;
            while ((info = br.readLine()) != null) {
                System.out.println("我是客户端,服务器说:" + info);
            }
            
            //4。关闭资源
            br.close();
            is.close();
            pw.close();
            os.close();
            socket.close();
        }
    }
    
    //我是客户端,服务器说:欢迎您!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    因为client要连接server端的某个端口建立TCP连接,所以要先运行server端程序,然后再运行client程序。

    accept()方法
    该方法一直监听端口,等待客户的连接请求,如果接收到一个连接请求,accept()方法就会返回一个Socket对象,这个Socket对象与客户端的Socket对象形成了一条通信线路

    输入/输出与两端交换数据
    Socket类提供了getInputStream()方法和getOutputStream()方法,分别返回输入流InputStream对象和输出流OutputStream对象。程序只需向输出流写数据,就能向对方发送数据;只需从输入流读数据,就能接收来自对方的数据。

     
     

    参考:
    【孙卫琴】java网络编程核心技术详解

  • 相关阅读:
    Ubuntu 配置
    larave使用sanctum进行API鉴权
    2022互联网企业Java岗面试总纲:JVM+分布式+Spring+算法数据结构
    TestStand-创建VI
    线程的学习5
    【编译原理】语法分析
    zabbix企业监控
    ElasticSearch学习笔记(狂神说)
    Circular view path [ ]: would dispatch back to the current handler URL 错误解决
    2.9.C++项目:网络版五子棋对战之业务处理模块的设计
  • 原文地址:https://blog.csdn.net/hiliang521/article/details/126480694