计算机网络的连环炮面试题

计算机网络面试核心

2-1 网络基础知识讲解

  1. 面试网络知识的意义?

    编程的时候并不需要编写Socket,并且底层服务已经很好的处理了数据包的解析。实际上网络知识就相当于框架底层知识,平时能够满足我们需求的时候并不会关心网络,但是如果性能没办法满足我们的需求时,就需要使用到网络知识。比如没办法判断程序为什么会变慢,是网络的原因还是其他原因,数据包有没有丢失,为什么会造成大量的Close Wait,为什么会出现大量的连接丢失等等。

  2. 网络协议

    国际标准化组织ISO制定的OSI七层开放式互联协议模型

    • 物理层:首先要解决两台物理机之间的通信需求,机器A向机器B发送比特流,机器B能够接收这些比特流。物理层主要定义了物理设备的标准,如网线的类型、光纤的接口类型、各种传输介质的传输速率,其作用是传输比特流即0101二进制数据,将他们转化为电流强弱来进行传输,到达目的地后再转换为0101机器码,此时用到数模转换器和模数转换器。这层数据是比特,网卡工作在物理层。
    • 数据链路层:在传输比特流的过程中会产生错传,数据传输不完整的可能,因此产生了数据链路层。数据链路层定义了如何格式化数据以进行传输,以及如何让控制对物理介质的访问。数据链层通常还提供错误检测和纠正以确保数据传输的可靠性,本层将比特数据组成了帧,交换机工作在数据链路层,对帧解码,并根据帧中包含的信息把数据发送到正确的接收方。
    • 网络层:随着网络节点的增加,点对点通信时需要经过多个节点,如何找到目标节点,如何选择最佳路径,此时便有了网络层。其主要功能是将网络地址翻译成对应的物理地址,并决定如何将数据从发送方路由到接收方,网络层通过综合考虑,发送优先权、网络拥塞程度、服务质量、可选路由的花费来决定从一个网络中节点A到另一个网络中节点B的最佳路径,由于网络层处理并智能指导数据传送,路由器连接网络各段,所以路由器属于网络层,此层的数据称为数据包。此层的协议有TCP/IP协议里边的IP协议。
    • 传输层:随着网络通信需求的进一步扩大,通信过程中需要发送大量的数据,如海量文件传输需要很长时间,而网络在通信的过程中会中断很多次,此时为了保证传输大量文件的正确性,需要对发出去数据进行切分,切割为一个一个的段落,即segment进行发送。其中一个段落丢失应该怎么处理,需不需要重传,每个段落需要按照顺序到达么,由此产生了传输层。传输层解决了主机间的数据传输,数据间的传输可以是不同网络的,并且传输层解决了传输质量的问题,是OSI模型中最重要的一层。传输协议同时进行流量控制或是基于接收方可接收数据的快慢程度规定适当的发送速率。传输层按照网络能够处理的最大尺寸将较长数据包进行强制分割,例如以太法无法接收大于1500字节数据包,发送方节点的传输层将数据分割成较小的数据片同时对每一数据片安排序列号以便数据到达接收方节点的传输层时以正确的顺序重组,该过程称为排序。协议有TCP/IP协议中的TCP协议和UDP协议。
    • 会话层:此时已经保证了给正确的计算机发送正确的封装过后的信息,但是用户级别的体验并不好,此时用户每次都需要调用TCP打包然后调用IP协议寻找路由然后发送,由此需要一个自动收发包,自动寻址的功能,于是产生了会话层。会话层的作用就是建立和管理应用程序之间的通信。
    • 表示层:需要表示成SESSION LAYER来解决不同系统之间通信语法的问题,在表示层数据将按照网络能够理解的方法来进行格式化,这种格式化也因为网络类型使用的不同而不同。
    • 应用层:此时发送方知道自己发送的是什么数据,转换成字节数组之后有多长,但接收方一无所知,所以产生了应用层的网络协议。应用层规定发送方和接收方必须使用一个固定长度的消息头,消息头必须使用某种固定的组成,而且消息头里必须记录消息体的长度等一系列信息以方便接收方能够正确的解析发送方发送的数据。此协议层有TCP/IP协议中的HTTP协议
    OSI七层开放式互联协议模型
  3. 数据处理流程

    先自上而下,后自下而上处理数据头部

    从应用层开始都会对要传输的数据头部进行处理,加上本层的一些信息,最终由物理层通过以太网、电缆等介质将数据解析成比特流在网络中传输,数据传递到目标地址后将自低而上的将数据头部解析分离出来。

    数据处理流程
  4. TCP/IP(传输/控制协议)

    OSI模型并不是一个标准,而是制定标准时使用的概念型框架

    OSI的“实现”:TCP/IP网际协议群

    TCP/IP(传输/控制协议) TCP/IP概念层模型

2-2 TCP的三次握手_1

  1. IP协议

    IP协议是无连接的通信协议,他不会占用两个正在通信的计算机之间的通信线路,这样IP就降低了对网络线路的需求,每条线可以同时满足许多不同的计算机之间的通信需要。通过IP、消息或者其他数据会被分割为较小的独立的包,并通过因特网在计算机之间传送。IP负责将每个包路由至他的目的地,但IP协议没有确认数据包是否按顺序发送或者包是否损坏,所以IP数据包是不可靠的,需要由他的上层协议作出控制。

  2. TCP协议(传输控制协议)

    • 面向连接的、可靠地、基于字字节流的传输层通信协议
    • 将应用层的数据流分割成报文段并发送给目标节点的TCP层
    • 数据包都有序号,对方收到则发送ACK确认,未收到则重传
    • 使用校验和检验数据在传输过程中是否有误
  3. TCP报文头

    TCP和UDP均不包含IP信息,但是包含了源端口和目的端口(端口属于传输层范畴)

    两个进程在计算机内部进行通信可以有管道、内存共享、信号量、消息队列等方法。

    通信前提:唯一的标识一个进程。本地通信中PID(进程标识符/进程号)来唯一标识进程,PID仅在本地唯一,两个进程在不同的计算机则可能重复。

    IP+协议+端口号唯一标识网络中的一个进程。套接字Socket模式

    TCP报文头
  4. TCP Flags:TCP控制位,由8个标志位来组成,每个标志位表示一个控制功能。

    • URG:紧急指针标志 1紧急指针有效;0忽略紧急指针
    • ACK:确认序号标志 1确认号有效;0报文中不含确认信息,忽略确认号字段
    • PSH:push标志 1是带有push标志的数据,指示接收方在接收到该报文段以后应尽快将该报文段交给应用程序,而不是在缓冲区排队
    • RST:重置连接标志 用于重置由于主机崩溃或者其他原因而出现错误的链接,或者用于拒绝非法的报文段和拒绝连接请求
    • SYN:同步序号 同于建立连接过程,在连接请求中SYN=1和ACK=0表示该数据段没有使用捎带的确认域,连接应答捎带确认则SYN=1和ACK=1
    • FIN:finish标志 用于释放连接,1表示发送方没有数据发送,即关闭本方数据流
  5. 说说TCP的三次握手

    当应用程序希望通过TCP与另一个程序通信时,他会发送一个通信请求,这个请求必须被送到一个确切的地址,在双方**“握手”之后TCP将在两个应用之间建立一个全双工的通信**,这个全双工的通信将占用两个计算机之间的通信线路,直到他被一方或双方关闭为止。

    全双工(Full Duplex):计算机A可以给B发送信息,同时B也能够给A发送信息

    “握手”是为了建立TCP连接,TCP三次握手的流程图如下:

    TCP三次握手

2-3 TCP的三次握手_2

Wireshark抓包工具

★在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。

  1. 第一次握手:建立连接时,客户端发送同步序号SYN包(seq=j seq初始序号任意正整数)到服务器,并进入SYN_SEND状态,等待服务器确认;不能消耗
  2. 第二次握手:服务器收到SYN包,必须确认客户的SYN(ack=j+1) ,同时自己也发送一个SYN包(seq=k) , 即SYN+ACK包,此时服务器进入SYN_RECV状态;
  3. 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,如果携带数据seq+1,没有就不消耗客户端和服务器进入ESTABLISHED状态,完成三次握手。

解析:seq是序列号,这是为了连接以后传送数据用的,ack是对收到的数据包的确认,值是等待接收的数据包的序列号。 在第一次消息发送中,A随机选取一个序列号作为自己的初始序号发送给B;第二次消息B使用ack对A的数据包进行确认,因为已经收到了序列号为x的数据包,准备接收序列号为x+1的包,所以ack=x+1,同时B告诉A自己的初始序列号,就是seq=y;第三条消息A告诉B收到了B的确认消息并准备建立连接,A自己此条消息的序列号是x+1,所以seq=x+1,而ack=y+1是表示A正准备接收B序列号为y+1的数据包。

seq是数据包本身的序列号;ack是期望对方继续发送的那个数据包的序列号。

★为什么需要三次握手才能建立起连接?

  • 为了初始化Sequence Number的初始值:通信的双方需要互相通知对方自己的初始化的Sequence Number,用此作为数据通信的序号以保证应用层上接收到的数据不会因为网络上的传输问题而乱序,即TCP会利用Sequence Number来拼接数据。因此在服务器回发Sequence Number,即第二次握手之后还需要发送确认报文给服务器告知服务器客户端已经收到服务器初始化的Sequence Number

首次握手的隐患—SYN超时

  1. 问题起因分析
    • Server收到Client的SYN,回复SYN-ACK的时候未收到ACK确认
    • Server不断重试直至超时,Linux默认等待63秒才断开连接 5次(1 2 4 8 16 32)
  2. 针对SYN Flood的防护措施
    • SYN队列满后,Linux通过tcp_syncookies参数回发SYN Cookie
    • 若为正常连接则Client会回发SYN Cookie,直接建立连接

建立连接后,Client出现故障怎们办

  1. 保活机制
    • 向对方发送保活探测报文,如果未收到回应则继续发送
    • 尝试次数达到保活探测数仍未收到响应则中断连接

2-4 TCP的四次挥手

  1. ★TCP采用四次挥手来释放连接
    • 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入到FIN_WAIT_状态;

    • 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态;

  • 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态;

    • 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,Client在经过2MSL时间也会进入CLOSED状态,完成四次挥手。

      MSL:最长报文段寿命,IFC793定义MSL为2分钟,而Linux定义为30秒

      TCP连接必须经过时间2MSL后才真正释放掉

    “挥手”是为了终止连接,TCP四次挥手的流程图如下(假设客户端触发Close):

    TCP四次挥手
  1. 为什么会有TIME_WAIT状态

    • 确保有足够的时间让对方收到ACK包。如果被动关闭的一方没有收到ACK则会重发FIN包,一来一去正好为2MSL

    • 避免新旧连接混淆。有足够的时间不会和后面的连接混在一起

  2. 为什么需要四次握手才能断开连接

    因为TCP是全双工,发送方和接收方都需要FIN报文和ACK报文。双方各只需两次挥手就可完成,所以看上去是4次挥手。

  3. 服务器出现大量的CLOSE_WAIT状态的原因

    对方关闭Socket连接,我方忙于读或写操作,没有及时关闭连接。

    • 检查代码,特别是释放资源的代码

    • 检查配置,特别是处理请求的线程配置

      Linux的netstat指令:

      netstat -n | awk '/^tcp/{++S[$NF]}END{for(a in S) print a, S[a]}/'
      

      获取该服务器处于各个状态下的连接数

      Linux服务器为每个用户分配有限的文件句柄数,连接和文件句柄一一对应。CLOSE_WAIT数目太多意味着对应数目的通道一直被占用,一旦达到上限则无法处理新的请求,此时会出现’too many open files’异常并造成软件服务器的崩溃

2-5 TCP和UDP的区别

UDP(User Datagram Protocol):用户数据报协议

  1. UDP报文结构:
    UDP报文结构

  2. UDP的特点:

    • 面向非连接
    • 不维护连接状态,支持同时向多个客户端传输相同的消息
    • 数据包报头只有8个字节,额外开销较小
    • 吞吐量只受限于数据生成速率、 传输速度以及机器性能影响
    • 尽最大努力交付,不保证可靠交付,不需要维持复杂的链接状态表
    • 面向报文,不对应用程序提交的报文信息进行拆分或者合并
  3. TCP和UDP的区别

    TCPUDP
    面向连接无连接
    可靠性
    有序性
    速度慢
    重量级

    TCP报文头20个字节,UDP只有8个字节

2-6 TCP的滑窗

RTT和RTO

  • RTT(Round Trip Time):发送一个数据包到收到对应的ACK所花费的时间
  • RTO(Retransmission TimeOut):重传超时时间、重传时间间隔。通过RTT计算得出RTO

TCP的滑动窗口

  1. TCP使用滑动窗口做流量控制与乱序重排

    • 保证TCP的可靠性
    • 保证TCP的流控特性

    流量控制:滑动窗口用于接收方通知发送方自己还有多少缓冲区可以接收数据,发送方根据接收方的处理能力来发送数据,不会导致接收方处理不过来

    滑动窗口机制还体现了TCP面向字节流的设计思路

  2. 窗口数据的计算过程:

    窗口数据的计算过程
    • AdvertisedWindow = MaxRecBuffer - (LastByteRcvd - LastByteRead)

      接收方还能接收处理的量 = 接收方能够接收的最大数据量(接收端缓存池大小) - (最后处理数据 - 最后读取数据)

    • EffectiveWindow = AdvertisedWindow - (LastByteSend - LastByteAcked)

      窗口内剩余可发送大小 = 接收方还能接收处理的量 - (最后发送数据 - 最后收到响应数据)

  3. TCP滑动窗口的基本原理

    发送窗口只有收到接收端对于本段发送窗口内字节的ACK确认才会移动发送窗口的左边界,接收窗口只有在前面所有的段都确认的情况下才会移动左边界,当在前面还有字节未接收但收到后面字节的情况下窗口是不会移动的并不对后续字节确认,以此确保对端会对这些数据的重传

    TCP会话的发送方

    TCP会话的发送方

    对于TCP会话的发送方,任何时候在其发送缓存内的数据都可以分为4类:

    1. 已经发送并且已经得到端的回应的数据
    2. 已经发送但还没有得到端的回应的数据
    3. 未发送但对端允许发送的数据
    4. 未发送且由于达到Window的大小,对方不允许发送的数据

    其中2、3称为滑动窗口

    TCP滑动窗口

    TCP会话的接收方

    TCP会话的接收方

    对于TCP的接收方,在某一时刻在其接收缓存内的数据会存在3种状态:

    1. 已接收并且已经发送回执的状态;

    2. 未接收但是可以接收的状态,即准备接收;

    3. 未接收并且不能接收的状态,达到窗口的阈值

      其中未接收但是可以接受的状态称为接收窗口,滑动机制。

      ACK直接由TCP栈回复,默认没有应用延迟,所以不存在已接收但是未回复的状态。

    TCP的传输可靠性和滑动窗口的可靠性依赖于确认重传机制

    滑动窗口的基本原理:

    • 发送窗口只有收到接收端对于本段发送窗口内字节的ACK确认才会移动发送窗口的左边界
    • 接收窗口只有在前面所有的段都确认的情况下才会移动左边界。当前面字节未接收但收到后面字节,窗口是不会移动的,并不对后续字节确认,以此确保发送端会对这些数据重传。

    滑动窗口的大小可以依据一定的策略动态调整,应用会根据自己处理能力的变化通过本端TCP接收端窗口大小的控制来实现对端的发送窗口进行流量限制

2-7 HTTP相关

  1. 超文本传输协议HTTP主要特点:
    支持客户/服务器模式
    简单快速
    灵活
    无连接
    无状态

  2. HTTP请求结构
    HTTP请求结构

  3. HTTP响应结构
    HTTP响应结构

  4. HTTP简介
    HTTP定义了WEB客户端如何从WEB服务器请求WEB页面,以及服务器如何把WEB页面传送给客户端,HTTP协议采用了请求/响应模型。

  5. 请求/响应的步骤:

    • 客户端连接到WEB服务器
    • 发送HTTP请求
    • 服务器接收请求并返回HTTP回应
    • 释放连接TCP连接
    • 客户端浏览器解析HTTP内容
  6. 在浏览器地址栏键入URL,按下回车之后经理的流程

    • DNS解析:浏览器会根据URL逐层查询DNS服务器缓存,解析URL中域名对应的IP地址。DNS从近到远依次是:浏览器缓存、系统缓存、路由器缓存、IPS服务器缓存、根域名服务器缓存、顶级域名服务器缓存。
    • TCP连接:根据IP地址浏览器和对应端口(默认是80端口)与服务器建立TCP连接,TCP三次握手
    • 发送HTTP请求:
    • 服务器处理请求并返回HTTP报文
    • 浏览器解析渲染页面
    • 连接结束:TCP四次挥手
  7. HTTP状态码

    五种可能的取值:

    • 1xx:指示信息–表示请求已接收,继续处理
    • 2xx:成功–表示请求已被成功接收、理解、接受
    • 3xx:重定向–要完成请求必须进行更进一步的操作
    • 4xx:客户端错误–请求有语法错误或请求无法实现
    • 5xx:服务器端错误–服务器未能实现合法的请求

    常见状态码:

    • 200 OK:正常返回信息
    • 400 Bad Request:客户端请求有语法错误,不能被服务器所理解;此时分析客户端代码
    • 401 Unauthorized:请求未经授权,这个状态码必须和WWW-Authenticate报头域一起使用
    • 403 Forbidden:服务器收到请求,但是拒绝提供服务
    • 404 Not Found:请求资源不存在,eg,输入了错误的URL;检查URL和路径配置
    • 500 Internal Server Error:服务器发生不可预期的错误
    • 503 Server Unavailable:服务器当前不能处理客户端请求,一段时间后可能恢复正常
  8. GET请求和POST请求的区别
    HTTP报文层面:GET将请求信息放在URL,POST放在报文体中
    数据库层面:GET符合幂等性存取一致和安全性不修改数据,POST不符合会修改数据并且每次获得的结果都可以能不一样,可能在上一级的url,因为post请求地址栏不变
    其他层面:GET可以被缓存、被存储,而POST不行

  9. Cookie和Session的区别:

    Cookie简介:

    • 是由服务器发给客户端的特殊信息,以文本的形式存放在客户端
    • 客户端再次请求的时候,会把Cookie回发
    • 服务长期接收到后,会解析Cookie生成与客户端相对应的内容

    Cookie的设置以及发送过程:
    Cookie的设置以及发送过程

    Session简介

    • 服务器端的机制,在服务器上利用散列表保存的信息
    • 解析客户端请求并操作session id,按需保存状态的信息

    Session的实现方式

    • 使用Cookie来实现
      Cookie实现
    • 使用URL回写来实现

    Tomcat支持两种实现方法,但不同时支持

    Cookie和Session的区别:

    • Cookie数据存放在客户的浏览器上,Session数据放在服务器上
    • Session相对于Cookie更安全
    • 若考虑减轻服务器负担,应使用Cookie

2-9 HTTP和HTTPS的区别

  1. HTTPS(Hypertext Transfer Protocol Secure):超文本传输安全协议
  2. SSL(Security Sockets Layer):安全套接层
    • 为网络通信提供安全及数据完整性的已终止安全协议
    • 位于TCP与个应用层之间,是操作系统对外的API,SSL3.0后更名为TLS
    • 采用身份认证和数据加密保证网络通信的安全和数据的完整性
  3. 加密的方式:
    • 对称加密:加密和解密都是用同一个密钥,效率高,安全性低
    • 非对称加密:加密使用的密钥和解密使用的密钥是不相同的,公钥私钥,安全性高,数据长度有限
    • 哈希算法:将任意长度的信息转换为固定长度的值,算法不可逆,常见算法:MD5
    • 数字签名:证明某个消息或者文件是从某人发出/认同的
  4. HTTPS数据传输流程:证书+加密方式
    • 浏览器将支持的加密算法信息发送给服务器
    • 服器选择一套浏览器支持的加密算法,以证书的形式回发给浏览器
    • 浏览器验证证书合法性,并结合证书公钥加密信息发给服务器
    • 服务器使用私钥解密信息,验证哈希,加密响应消息回发给浏览器
    • 浏览器解密响应消息,并对消息进行验证,之后进行加密交互数据
  5. Http和HTTPS的区别:
    • HTTPS需要到CA机构申请证书,HTTP不需要
    • HTTPS密文传输,HTTP明文传输
    • 连接方式不同,HTTPS默认使用443端口,HTTP模式使用80端口
    • HTTPS=HTTP+加密+认证+完整性保护,较HTTP安全
  6. HTTPS真的安全么
    • 浏览器默认填充http://,请求需要进行跳转,有被劫持的风险
    • 可以使用HSTS(HTTP Strict Transport Security)优化

2-10 socket相关

Socket是对TCP/IP协议的抽象,是操作系统对外开放的接口
Socket抽象层

Socket通信流程:
Socket通信流程

Socket相关面试题:

  • 编写一个网络应用程序,有客户端与服务器端,客户端向服务器发送一个字符串,服务器收到该字符串后将其打印到命令行上,然后向客户端返回该字符串的长度,最后,客户端输出服务器端返回的该字符串的长度,分别用TCP和UDP两种方式去实现

    TCP实现方式

    • 服务器端
      public class TCPServer {
          public static void main(String[] args) throws Exception {
              //创建Socket,并将socket绑定到6500端口
              ServerSocket serverSocket = new ServerSocket(6500);
              //死循环,使得Socket一直等待并处理客户端发送过来的请求
              while (true) {
                  //监听6500端口,知道客户端返回连接信息才返回
                  Socket socket = serverSocket.accept();
                  //获取客户端的请求信息后,执行相关业务逻辑
                  new LengthCalculator(socket).start();
              }
          }
      }
      
    • 客户端
      public class TCPClient {
          public static void main(String[] args) throws Exception {
              //创建socket,并指定连接的是本机的端口号6500的服务器socket
              Socket socket = new Socket("127.0.0.1", 6500);
              //获取输出流
              OutputStream outputStream = socket.getOutputStream();
              //获取输入流
              InputStream inputStream = socket.getInputStream();
              //将要传递给server的字符串参数转换成byte数组,并将数组写入到输出流中
              outputStream.write("hello world".getBytes());
              int ch = 0;
              byte[] buff = new byte[1024];
              //buff主要与塞拉读取输入的内容,存成byte数组,ch主要用来获取数组的长度
              ch = inputStream.read(buff);
              String content = new String(buff, 0, ch);
              System.out.println("content = " + content);
              //不要忘记关闭输入输出流及socket
              outputStream.close();
              inputStream.close();
              socket.close();
          }
      }
      
      public class LengthCalculator extends Thread {
          //以socket为成员变量
          private Socket socket;
      
          public LengthCalculator(Socket socket) {
              this.socket = socket;
          }
      
          @Override
          public void run() {
              try {
                  //获取socket的输出流
                  OutputStream outputStream = socket.getOutputStream();
                  //获取socket的输入流
                  InputStream inputStream = socket.getInputStream();
                  int ch = 0;
                  byte[] buff = new byte[1024];
                  //buff主要用来读取输出的内容,存成byte数组,ch主要用来获取读取数组的长度
                  ch = inputStream.read(buff);
                  //将接收流的byte数组转成字符串,这里获取的内容是客户端发送过来的字符串参数
                  String content = new String(buff, 0, ch);
                  System.out.println("content = " + content);
                  //网输出流里写入获取的字符串的长度,回发给客户端
                  outputStream.write(String.valueOf(content.length()).getBytes());
                  //不要忘记关闭输入输出流以及socket
                  outputStream.close();
                  inputStream.close();
                  socket.close();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
      

    UDP实现方式

    • 服务器端
      public class UDPServer {
          public static void main(String[] args) throws Exception {
              //服务端连接客户端发送的数据报
              DatagramSocket socket = new DatagramSocket(65001);//监听的端口号
              byte[] buff = new byte[1024];//存储从客户端接收到的内容
              DatagramPacket packet = new DatagramPacket(buff, buff.length);
              //接收客户端发送过来的内容,并将内容封装进DatagramPacket对象中
              socket.receive(packet);
      
              byte[] data = packet.getData();//从DatagramPacket对象中获取到真正存储的数据
              //将数据中二进制转换成字符串形式
              String content = new String(data, 0, packet.getLength());
              System.out.println("content = " + content);
              //将要发送给客户端的数据转换成二进制
              byte[] sendedContent = String.valueOf(content.length()).getBytes();
              //服务端给客户端发送数据报
              //从DatagramPacket对象中获取到数据的来源的地址与端口号
              DatagramPacket packetToClient = new DatagramPacket(sendedContent, sendedContent.length,
                      packet.getAddress(), packet.getPort());
              socket.send(packetToClient);//发送数据给客户端
          }
      }
      
    • 客户端
      public class UDPClient {
          public static void main(String[] args) throws Exception {
              //客户端发送数据报给服务端
              DatagramSocket socket = new DatagramSocket();
              //要发送给服务端的数据
              byte[] buff = "hello world".getBytes();
              //将IP地址封装成InetAddress对象
              InetAddress address = InetAddress.getByName("127.0.0.1");
              //将要发送给服务端的数据封装成DatagramPacket对象 需要填写上IP地址和端口号
              DatagramPacket packet = new DatagramPacket(buff, buff.length, address, 65001);
              //发送数据给服务器
              socket.send(packet);
      
              //客户端接收服务器发送过来的数据报
              byte[] data = new byte[1024];
              //创建DatagramPacket对象用来存储服务期初发送火来的数据
              DatagramPacket receivedPacket = new DatagramPacket(data, data.length);
              //将要接收到的数据存储到DatagramPacket对象中
              socket.receive(receivedPacket);
              //将服务器端发送过来的数据取出来并打印到控制台
              String content = new String(receivedPacket.getData(), 0, receivedPacket.getLength());
              System.out.println("content = " + content);
          }
      }
      

2-11 网络知识总结

  1. IPV4和IPV6:
网络知识总结
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵广陆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值