java 网络字节序转主机字节序_计算机网络常见面试题

1.键入URL之后的过程

2.UDP如何实现可靠传输?

UDP要想可靠,就要接收方收到UDP之后回复个确认包,发送方有个机制,收不到确认包就要重新发送,每个包有递增的序号,接收方发现中间丢了包就要发重传请求,当网络太差时候频繁丢包,防止越丢包越重传的恶性循环,要有个发送窗口的限制,发送窗口的大小根据网络传输情况调整,调整算法要有一定自适应性。

即在应用层实现TCP,但又避免了TCP拥塞控制和慢启动的缺点

3.如何保证TCP可靠传输?

  • 校验和:目的是检测数据在传输过程的是否出现了变化;如果接收端发现校验和有差错,就丢弃这个报文段
  • 确认应答+序列号:发送端给每个报文段进行编号,接收端收到报文后,都会进行确认应答,即ACK报文,其中包含确认序列号,告诉对方接收到了数据,下一次的数据从哪里发。并且丢弃收到的重复序列号的数据。
  • 重传:超时重传和快速重传,以及带选择确认的重传。超时重传:TCP每发送一个段后,启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。对同一报文的重传超时,每次增加一倍;快速重传:发送端收到若干个重复ACK时,就认为有报文丢失了,立刻重传,不需等到计时器到时;带选择确认的重传:当采用SACK选项时,一个ACK可以包含三四个告知失序数据的SACK信息。(SACK选项指定n个块的长度8*n+2字节,因此40个字节,最多4个块,4个块表示发送端可以报告3个空缺),从而在一个往返时间内,通知多个丢包。
  • 流量控制:发送端的发送速度大于接收端处理数据的速度,就有可能导致新发来的数据丢失。接收端和发送端都一个窗口结构,窗口内的字节是正在处理的,若接收方处理不过来,就通知发送方将发送窗口缩小。

f84ddec04916a2ed64293224aa48f1f0.png
发送端窗口

e1143c3c8f9a215e049a5ccf2330d34f.png
接收端窗口
  • 拥塞控制:路由器因无法处理高速到达的流量而被迫丢弃数据信息的现象称为拥塞。TCP主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快速重传、快速恢复。

eace71e7bb9cd3a45cf65903e5bac53a.png
拥塞控制

4.TCP中ack和seq号的计算

(1)三次握手和四次挥手时

8a515c400949032d2a891effe0372c7e.png
seq=x和seq=y是随机生成的序列号(如何初始化和系统具体实现有关)

5415de8f5b22ab7ee5856ff5d964e863.png
seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1)

(2)数据传输阶段

ack号就是下一次将要收到包的序号。同时也等于发送方的序号+数据长度

(3)总结:

  • seq号:除了初始连接的seq号是随机生成的,其余每次seq号都是上一次从该端发送的seq+上一次发送长度(若没有数据,则FIN和SYN都是一个字节,若有数据,则还要加上数据长度)
  • ack号:期望下一次对方的seq号是多少。上一次对方发来的seq+len

5.关于初始序列号的选择

同一连接的不同实例之间的序列号也不能出现重叠,防止TCP报文段在经过网络路由之后可能会存在延迟抵达与排序混乱的情况。并且如果选择合适的序列号、IP地址和端口号,那么任何人都可以伪造出一个TCP报文段,打断TCP正常连接。随机选择序列号也是抵御这种攻击的方法之一。

6.网络传输中大小端

(1)小端:低地址存放的是数据的低位;大端:低地址存放的是数据的高位

(2)为什么要分大小端?因为各个CPU厂商出于不同的逻辑考量,主机的字节序不统一。

(3)如何解决通信双方大小端不一致的问题?

  • 编程之前,用文档约束好,服务器采用的是大端或者小端,然后客户端根据自己的大小端情况去转换成与服务器一样的字节序再发送和接受;
  • 客户端连接服务器后,服务器先发送一个表示大小端的1字节的数据到客户端,客户端接收后得知服务器的大小端,以后发送和接收数据时作大小端的调整再发送和接收。

7.DNS用的是TCP协议还是UDP协议?

DNS占用53号端口,同时使用TCP和UDP协议。DNS在区域传输的时候使用TCP协议,其他时候使用UDP协议。

  • DNS区域传输的时候使用TCP协议:辅域名服务器会定时(一般3小时)向主域名服务器进行查询以便了解数据是否有变动。如有变动,会执行一次区域传送,进行数据同步。区域传送使用TCP而不是UDP,因为数据同步传送的数据量比一个请求应答的数据量要多得(TCP是一种可靠连接,保证了数据的准确性)
  • 域名解析时使用UDP协议:客户端向DNS服务器查询域名,一般返回的内容都不超过512字,用UDP传输即可。不用经过三次握手,这样DNS服务器负载更低,响应更快。

8.什么时候使用select比使用epoll要好?

如果在并发量低,socket都比较活跃的情况下,select就不见得比epoll慢了(就像我们常常说快排比插入排序快,但是在特定情况下这并不成立)。

一个游戏服务器,tcp server负责接收客户端的连接,dbserver负责处理数据信息,一个webserver负责处理服务器的web请求,gameserver负责游戏的逻辑处理,所有这些服务都和另外一个gateserver相连,gateserver负责服务器间的通信和转发(进程间通信),只要游戏服务器在服务状态,这些连接几乎不会断开(异常情况可能会断开),并且这些连接数量一般不会很多。这种情况,select还是epoll呢?很明显是select,因为每时每刻这些连接的socket都有事件发生(比如:服务期间的心跳信息,还有大型网络游戏的同步信息(一般每秒在20-30次)),最重要的是,这种场景下,并发量也不会很大。如果此时用epoll,为此所建立的文件系统,红黑书和链表对于此来说就是杀鸡用牛刀,效率反而不高。当然这里的tcp server负责大量的客户端的连接,毫无疑问epoll是首选,它接受大量的客户端连接,收到客户端的消息之后把消息转发发给select网络模型的gateserver,gateserver再转发给gameserver进行逻辑处理,最后返回给客户端就over了。

9.TCP如何保证包的顺序传输?

  • 主机每次发送数据时,TCP就给每个数据包分配一个序列号并且在一个特定的时间内等待接收主机对分配的这个序列号进行确认
  • 如果发送主机在一个特定时间内没有收到接收主机的确认,则发送主机会重传此数据包。
  • 接收主机利用序列号对接收的数据进行确认,以便检测对方发送的数据是否有丢失或者乱序等
  • 接收主机一旦收到已经顺序化的数据,它就将这些数据按正确的顺序重组成数据流并传递到高层进行处理。

10.基于UDP和TCP的应用层协议

  • 基于TCP:FTP,SMTP,HTTP,HTTPs,SSH,Telnet,POP3
  • 基于UDP:TFTP(Trivial File Transfer Protocol (简单文件传输协议)),SNMP(Simple Network Management Protocol, 简单网络管理协议)用于网络信息的收集和网络管理,NTP(Network Time Protocol,网络时间协议)用于网络同步,DHCP(动态主机配置协议,动态配置IP地址)DNS

11.MTU和MSS的区别

  • MTU: Maxitum Transmission Unit 最大传输单元,这是链路层所能承载的最大帧数据部分大小,对于以太网来说就是1500bytes
  • MSS:Maxitum Segment Size 最大分段大小,因为TCP不希望IP层对数据进行分片,所以MSS的大小通常小于等于(MTU-TCP头部大小-IP头部大小),对于以太网来说就是1460bytes

12.MSL,TTL,RTT的区别

  • MSL:Maximum Segment Lifetime,报文段最大生存时间,这是任何报文在网络上存在的最长时间,超过这个时间将会被丢弃
  • TTL:time to live,生存时间,由源主机设置的初始值,并不是真正的时间,而是一个计数,存储了一个ip数据报可以经过的最大路由数,每经过一个路由器,该值减一。当此值为0的时候,数据报将会被丢弃
  • RTT:round-trip time,客户端到服务器端所花的是时间
  • 2MSL:tcp的time_wait状态也称为2MSL状态。设置2MSL之后关闭连接,是为了防止最后一个ACK丢失(拓展:①2MSL状态时,两端端口均不可用;②2MSL状态时,任何迟到的报文都将丢弃)

13.TCP和UDP的socket编程

6cb374bb1daccab035396a08ef07f511.png

4087c1c7b7b6273b3905e5ec54fe66ef.png

14.TCP长连接和短链接

(1)短链接:client向server发起连接请求,server接到请求,然后双方建立连接。client向server发送消息,server回应client,然后一次读写就完成了,这时候双方任何一个都可以发起close操作,不过一般都是client先发起close操作。

(2)长连接:Client与server完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。

(3)TCP保活功能:主要针对服务器端,在一段时间内双方没有互相发送数据,则需要判断是没有数据还是连接断开了

实现:保活机制是由一个保活计时器实现的,当计时器被激发,连接一端发送一个保活探测报文,另一端接收报文的同时发送一个ACK作为相应。保活时间:默认2小时;保活时间间隔:默认75秒;保活探测次数:默认9次(注:保活功能在默认情况下是关闭的。没有经过应用层的请求,Linux系统不会提供保活功能。)

发送完保活探测报文后

  • 对方主机仍在工作,并且可以到达。此时请求端将保活计时器重置。如果在计时器超时之前应用程序通过该连接传输数据,计时器再次被设定为保活时间值。
  • 对方主机已经崩溃,包括已经关闭或者正在重新启动。这时对方的TCP将不会响应。请求端不会接收到响应报文,并在经过保活时间间隔指定的时间后超时。超时前,请求端会持续发送探测报文,一共发送保活探测数指定次数的探测报文,如果请求端没有收到任何探测报文的响应,那么它将认为对方主机已经关闭,连接也将被断开。
  • 客户主机崩溃并且已重启。在这种情况下,请求端会收到一个对其保活探测报文的响应,但这个响应是一个重置报文段RST,请求端将会断开连接。
  • 对方主机仍在工作,但是由于某些原因不能到达请求端(例如网络无法传输,而且可能使用ICMP通知也可能不通知对方这一事实)。这种情况与状态2相同,因为TCP不能区分状态2与状态4,结果是都没有收到探测报文的响应。

保活的优缺点:避免频繁的建立和关闭连接;占用大量的带宽

15.SYN攻击及其解决方法

定义:SYN泛洪是一种TCP拒绝服务攻击,在这种攻击中一个或多个恶意的客户端产生一系列TCP连接尝试(SYN报文段),并将它们发送给一台服务器,通常采用“伪造”的源IP地址。服务器会为每一条连接分配一定数量的连接资源。由于连接尚未完全建立,服务器为了维护大量的半打开连接会在耗尽内存后拒绝后续合法的请求连接

解决方法:SYN cookies。当SYN到达时,不需要为进入的连接请求分配任何存储资源——只有当SYN+ACK报文段本身被确认后(并且已返回初始序列号)才会分配真正的内存。在执行SYN cookies时,需要仔细选择初始序列号,通常是由连接四元组,服务器端MSS和计时器进过hash之后的一个值。当收到客户端的ACK之后,如果根据计时器可以计算出与加密的hash值相同的结果,那么服务器会为这个连接分配资源。

16.GET和POST的区别

(1)GET——从指定的资源请求数据

/test/demo_form.asp?name1=value1&name2=value2
  • 查询字符串(Key/Value)是在GET请求的URL中发送的
  • GET请求可以被缓存,保留在浏览器的历史记录中,被收藏为书签
  • GET请求有长度限制
  • GET请求只应当用于取回数据

(2)POST——向指定的资源提交要被处理的数据

POST /test/demo_form.asp HTTP/1.1
Host: w3schools.com
name1=value1&name2=value2
  • 查询字符串(Key/Value)是在POST请求的HTTP消息主体中发送的
  • POST请求不会被缓存,不会保留在历史记录中,不能被收藏为书签中
  • POST请求对数据长度没有要求

cd5bed83b7456f55bb40c044dfeaf399.png

17.TCP粘包和拆包

(1)定义

由于TCP传输协议面向流的,没有消息保护边界。一方发送的多个报文可能会被合并成一个大的报文进行传输,这是粘包;也可能发送的一个报文被拆成多个小报文,这是拆包

b03cd374fda2be99f89f27fa0514265f.png

(2)粘包/拆包产生的原因

  • socket缓冲区和滑动窗口
  • MSS/MTU限制
  • Nagle算法

① socket缓冲区和滑动窗口

每个TCP socket在内核中都有一个发送缓冲区(SO_SNDBUF )和一个接收缓冲区(SO_RCVBUF),TCP的全双工的工作模式以及TCP的滑动窗口便是依赖于这两个独立的buffer的填充状态。

SO_SNDBUF:send()函数将用户缓冲区的数据拷贝到内核缓冲区,但不一定就发送了

SO_RCVBUF:read()函数将内核缓存区的数据拷贝到用户缓冲区,如果不read,就一直保存在内核缓存区中

滑动窗口:TCP连接在三次握手的时候,会将自己的窗口大小(window size)发送给对方,其实就是SO_RCVBUF指定的值。之后在发送数据的时,发送方必须要先确认接收方的窗口没有被填充满,如果没有填满,则可以发送。如果对方的window size=0时,就会停止发送,并且等到对方发送一个窗口更新报文后,才发送

② MSS/MTU限制

MTU(最大传输单元):链路层对一次可以发送的最大数据限制。MSS(最大段大小):TCP报文中data部分的最大部分。这两个限制导致了发送方发送数据时,当SO_SNDBUF中的数据量大于MSS时,操作系统会将数据进行拆分,使得每一部分都小于MSS,也形成了拆包

③ Nagle算法(防止传送大量小包导致的效率低下问题)

Nagle算法的规则:

  1. 如果SO_SNDBUF中的数据长度达到MSS,则允许发送;
  2. 如果该SO_SNDBUF中含有FIN,表示请求关闭连接,则先将SO_SNDBUF中的剩余数据发送,再关闭;
  3. 设置了TCP_NODELAY=true选项,则允许发送。TCP_NODELAY是取消TCP的确认延迟机制,相当于禁用了Negale 算法。正常情况下,当Server端收到数据之后,它并不会马上向client端发送ACK,而是会将ACK的发送延迟一段时间(假一般是40ms),它希望在t时间内server端会向client端发送应答数据,这样ACK就能够和应答数据一起发送,就像是应答数据捎带着ACK过去。当然,TCP确认延迟40ms并不是一直不变的,TCP连接的延迟确认时间一般初始化为最小值40ms,随后根据连接的重传超时时间(RTO)、上次收到数据包与本次接收数据包的时间间隔等参数进行不断调整。另外可以通过设置TCP_QUICKACK选项来取消确认延迟。
  4. 未设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送;
  5. 上述条件都未满足,但发生了超时(一般为200ms),则立即发送。

(3)拆包粘包的解决策略

消息定长;设置消息边界;设置消息头(包括消息总长度);序列化

18.网络传输与字节序

(1)起因:网络上传输数据,因为发送端和接收端,通常不能保证是两边是相同的编程语言,就算都是使用C语言,CPU字节序,或者CPU位数不一样,直接将结构体的数据整理成流发送过去,数据排序或者长度会跟你想象的不一样。

比如:对于int等数据类型存在大小端问题,现有一32位int型数0x12345678

6b6067e308220db2df09c01d8cc2a56c.png

大端:将高字节存放到内存的低地址(0x12是高字节,0x78是低字节)

小端:将高字节存放到内存的高地址

(2)如何确定大小端

#include <stdio.h>
 
// 共用体中很重要的一点:a和b都是从u1的低地址开始存放的。
// 假设u1所在的4字节地址分别是:0、1、2、3的话,那么a自然就是0、1、2、3;
// b所在的地址是0而不是3.
 
union myunion
{
	int a;
	char b;
};
 
// 如果是小端模式则返回1,小端模式则返回0
int is_little_endian(void)
{
    union myunion u1;
    u1.a = 0x12345678;				// 地址0的那个字节内是0x78(小端)或者0x12(大端)
    if(0x78 == u1.b)
        return 1;
    else if(0x12 == u1.b)
	return 0;
}
 
int is_little_endian2(void)
{
    int a = 0x12345678;
    char b = *((char *)(&a));		// 指针方式其实就是共用体的本质
    if(0x78 == b)
        return 1;
    else if(0x12 == b)
	return 0;
}
 
 
int main(void)
{
	int i = is_little_endian2();
	//int i = is_little_endian();
	if (i == 1)
	{
		printf("小端模式n");
	}
	else
	{
		printf("大端模式n");
	}
	
	return 0;
}

(3)大小端网络传输

为了保证发送和接收的数据一致,需要进行主机字节序和网络字节的转换。

  • 主机字节序:大端和小端
  • 网络字节序:规定使用大端

htons 把unsigned short类型从主机序转换到网络序

htonl 把unsigned long类型从主机序转换到网络序

ntohs 把unsigned short类型从网络序转换到主机序

ntohl 把unsigned long类型从网络序转换到主机序

当消息中有整型,浮点型(应尽量避免使用)的时候需要用htonl,htons,ntohl,ntohs等函数转换一下,字符串由于是单字节排序的不需要转换

(4)序列化

如果对于每个数据类型都要手动用htonl之类的函数序列化,那么太麻烦,其实网络上有专门的序列化库,比如google的protobuff,boost也有相应模块,Qt的QDataStream内部就实现了序列化,序列化实际上就是把大小端,还有结构体字节对齐等细节屏蔽了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值