程序员

网络知识-疑惑自解

2017-01-03  本文已影响0人  小小青蛙不怕风吹雨打

TCP/IP相关的网络知识整理。一些疑惑的简单理解。

一些名词的解析

  1. 连接:收包方需要确认收到,就是有连接。TCP就需要ACK确认。
    ACK超时没收到,TCP会重发数据包。
  2. 顺序:收包顺序和发包顺序一致是有序的。TCP这种流式协议是有序的,udp这种数据报是无序的。
  3. 边界:边界用于确认收到一个完整的包。TCP是流协议,需要应用层区分;UDP 的recv返回值>=0,就是单个包的长度了。
    UDP的一种丢包:UDP的recv传入的缓存空间要是小于内核收到的数据报大小,这个数据报将被丢弃。
  4. MTU:最大传输单元,可以理解成IP层最大的分片大小,超出这个大小,就需要分片了。
    这个值一般由链路层限制,以太网:1500,PPPoE:1492,X.25协议:576。UDP常常限制包大小为1400或者512。
    可以用ping命令检测这个值,例如:ping -l 1600 -f www.baidu.com会返回需要分片的信息。

一些疑惑自解

  1. TCP的ACK包的ack一般都是syn+payload,SYN和FIN的ack为什么要+1,他们的payload是0啊?
    答:如果不+1无法确认收到。用FIN就好理解了,如果ack不+1,那么不能区分这个ACK是确认之前的数据全部收到还是确认这个FIN收到了。
  2. UDP的包长度有限制吗?TCP会自己分片数据送给ip层传输,UDP怎么处理,它的包怎么分片的?
    答:UDP报文的长度字段是有两个字节的。UDP直接把包交给ip层,IP层自己根据MTU分配,目标机器的ip层组装。所以最好是限制大小1400,避免被分片。
  3. IP层分片重组怎么判断重组失败,丢弃整个数据报?用定时器吗?
    答:不用定时器?收到分片时,会检查内存消耗,这时清理最旧的分片,相应的数据包也就不能重组成功了。

    一个blog http://blog.chinaunix.net/uid-22577711-id-3219806.html

  4. accept函数返回的socket连接和listen的socket是同一个吗?
    答:不是同一个。accept成功会生成一个新的socket,这个socket连接与listen的socket的ip和端口一样,不一样是这个socket是已连接的,可以获取到客户端的ip和端口。

怎么确定连接断掉了。

TCP要确认,UDP就不用了。

  1. recv返回==0,对端关闭连接。
  2. recv返回<0,检查下errno。如果是errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN,连接还是正常的,其他的连接断掉了。
  3. 使用getsockopt判断连接是否异常。一个简单的判断,只要有错误,就认为连接断掉了。
{
    int type = 0;
    socklen_t typesize = sizeof(type);
    int iCode = getsockopt(socket_id, SOL_SOCKET, SO_ERROR, (char*)&type, &typesize);
    return (iCode == 0);
}

有个特殊情况:TCP连接的一端奔溃后,对端是收不到任何信息的。
这个时候需要心跳包了:

  1. TCP本身提供了keep-alive机制,当TCP连接不使用一段时间后,发keep-alive包检测下。
    补充:keep-alive默认是不开的。一般服务器用,避免半连接占用资源。
  2. 应用层自己收发心跳包,确定连接是否正常。好处:可以同时支持TCP和UDP,可以计算延时啥的。
    补充:应用层缓冲区满了,可以直接认为连接不可用,比较方便,毕竟应用层的缓冲区一般是很大的。

PS:在学习样例里SetKeepAlive的函数,兼容windows、mac、linux

为什么要用TCP_NODELAY,TCP的延时问题是怎么样的

很多文章会说到这个。这里简单描述下。
延迟确认与Nagle算法同时起作用时,会造成延时增加。描述起来是这样一个情况:

  1. 客户端发送第一个小数据包
  2. 服务器收到,触发延迟确认
  3. 客户端发送第二个小数据包,但是第一个包还没收到ACK,触发Nagle算法,延迟发送。

问题就来了,第二个小数据包要等待服务器超时确认后才发送。
有选项解决这个问题:

  1. TCP_NODELAY:关闭Nagle算法,小包立即发送
  2. TCP_QUICKACK:关闭延迟确认,只生效一次,需要每次recv后重新设置

PS:还有个问题会增加延时,TCP有超时重传的机制,丢包后延时不可避免要增加。这个超时时间由系统决定。
所以对时效性要求高的应用(如:实时对战游戏)会选择UDP,浪费带宽,快速重传。

PS:在学习样例里SetNoBlock的函数,兼容windows、mac、linux

组播是个什么东西。单播和广播比较好理解,组播不清楚具体怎么工作的。

ipv4和ipv6里都有专门的组播地址,标识的是一个组而不是单独终端。
一般编程用不到,大概是路由器层面才用到。
组播地址列表。

ipv6没有广播地址255.255.255.255,但是有特殊的多播地址FF02::1,同样的作用。

奇怪的问题

  1. UDP的bind出错,错误码10022,错误消息“提供了一个无效的参数”。
    windows上,udp的socket先connect,再bind出这个错误。bind需要在connect之前调用

  2. 开发测试时,把本机同时当成客户端和服务器端,wireshark不能抓取数据包。设置路由解决。
    例如本地ip是192.168.2.186,网关是192.168.0.1。
    添加路由:route add 192.168.2.186 mask 255.255.255.255 192.168.0.1 metric 1
    删除路由:route delete 192.168.2.186 mask 255.255.255.255 192.168.0.1 metric 1

    参考blog http://www.cnblogs.com/luhouxiang/p/3606976.html

上一篇 下一篇

猜你喜欢

热点阅读