运输层UDP、TCP网络概念辨析以及socket编程流程图示
2016-10-03 12:04
483 查看
OUTLINE
udp和tcp区别
udp遇见包丢失怎么办,设计一下
udp的包如果出现错误怎么办?上层保证吗
差错检测可以百分百检错吗
有哪些校验和计算方法
TCP如何保证可靠传输、沾包
Linux下高并发socket最大连接数
linux下高性能网络框架,一个服务器连成千上万socket怎么办
RFID项目中服务器需要连多个客户,如何receive消息。
根据应用程序的不同需求,运输层需要两种协议:
面向连接的TCP(transmission control protocol)协议
无连接的UDP(User datagram protocol)协议
两者区别在于:
UDP是无连接的,TCP是面向连接的
UDP尽最大努力交付报文,TCP保证可靠交付。
UDP是基于报文的,并不合并或拆分上层交下来的报文,而是添加首部后交给IP层。TCP是基于byte流的。
[2]从更多的角度比较:
UDP是message-based无连接协议,也就是发送数据之前不需要建立专用的端到端连接。传输数据的时候也不需要检查接收方的readiness和状态。
1)不保证交付
UDP message发送之后便无法知道其状态了,有可能顺利到达接收方,也可能丢失。UDP没有确认收到、重传、超时这些概念。
2)无序的
3)轻量级,只是在IP的数据报服务之上增加了很少一点功能[1]
4)datagrams
Packets相互独立发送,并且各自有明确的边界。如果发送方一个packet,那接收方一定原样收到。
5)无拥塞控制
UDP本身不提供拥塞控制,如有必要,拥塞控制方法应该在应用层实现。
6)支持广播
而TCP是connection-oriented协议。意味着通信之前必须通过三次握手建立端到端连接。连接建立后,双方都可以通过这个连接发送数据。特点是
1)可靠交付
这里的可靠只限于传输层。在应用层,仍然需要一个独立的acknowledgement flow control。
TCP管理message确认、重传和超时。
这里提到If it gets lost along the way, the server will re-request the lost part.这和[1]中提到可靠传输过程不符:
接收方不需要请求重传某个出错的分组。因为发送方每发完一个分组会设置一个超时计时器,如果超时计时器到期,发送方没有收到接收方对前一个分组的确认。那么发送方会自动重传。
在TCP中只有两种情况:1. 所有数据正确发送 2. 网络已经断掉,超时多次。
2)有序的
3)重量级,支持可靠交付和拥塞控制
4)数据以stream的方式读入。没有message(segment)的明显边界
首先讨论这些名词的联系,他们都可以叫做PDU(protocol data unit)[3],也就是通信协议使用的数据单元。
[1]中使用的是TPDU(transport protocol data unit)。
所以他们的区别在于所在的协议不同。
在传输层叫segment(报文段)
在网络层叫datagram(数据报)
在数据链路层叫frame(帧)
他们可以统称为packet(分组)。
个人认为message和packet同义,比如[3]中这几句可以证明:
But in other cases the term "segment" includes the whole TCP message, including the TCP headers.
A single whole IP message is a "datagram".
The original IP RFC refers to link-layer messages as "packets".
而纠错的方式有两种:
1)Automatic repeat request (ARQ),网络中用的这种。
2)Forward error correction (FEC)
差错检测方式(Error detection schemes)包括:
1 Repetition codes
2 Parity bits
3 Checksums
4 Cyclic redundancy checks (CRCs)
5 Cryptographic hash functions
6 Error-correcting codes
其中checksum是通过某种算术公式把原始数据算出算术和。
CRC是不安全的哈希函数,用来检测数据中随机错误。
UDP和TCP的校验和不仅要对整个IP协议负载(包括UDP/TCP协议头和UDP/TCP协议负载)进行计算,还要先对一个伪协议头进行计算:先要填充伪首部各个字段,然后再将UDP/TCP报头及之后的数据附加到伪首部的后面,再对伪首部使用校验和计算,所得到的值才是UDP/TCP报头部分的校验和。[5]
具体计算方法是:
1)首先把校验和字段清零;
2)然后对每 16 位(2 字节)进行二进制反码求和;
反码求和时,最高位的进位要进到最低位,也就是循环进位。
接收方进行校验:按二进制反码求这些16bit字的和。若不差错,结果应为全1
传输过程可能出现两方面问题:
信道产生差错
接收方来不及处理收到的数据
TCP通过停止等待协议、滑动窗口来规避以上问题。
其中,停止等待协议指每发送完一个包就停止发送,等待对方确认。
停止等待协议的设计采用超时重传机制。
连续ARQ协议是滑动窗口的简化模型。
附:连接建立三次握手,连接释放四次挥手示意图。
注意,作者server端口范围方面的观点有误,具体见5.2
原文摘要:
1)用户进程可打开文件数限制
在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每个TCP连接都要创建一个socket句柄,每个socket句柄同时也是一个文件句柄)。
这表示当前用户的每个进程最多允许同时打开1024个文件
2)网络内核对TCP连接的有关限制
内核对本地端口号范围的限制(误)
Linux网络内核的
3)使用支持高并发网络I/O的编程技术
在Linux上编写高并发TCP连接应用程序时,必须使用合适的网络I/O技术和I/O事件分派机制。
可用的I/O技术有同步I/O,非阻塞式同步I/O(也称反应式I/O),以及异步I/O。
在高TCP并发的情形下,如果使用同步I/O,这会严重阻塞程序的运转,除非为每个TCP连接的I/O创建一个线程。但是,过多的线程又会因系统对线程的调度造成巨大开销。因此,在高TCP并发的情形下使用同步 I/O是不可取的,这时可以考虑使用非阻塞式同步I/O或异步I/O。非阻塞式同步I/O的技术包括使用select(),poll(),epoll等机制。异步I/O的技术就是使用AIO。
从I/O事件分派机制来看,使用select()是不合适的,因为它所支持的并发连接数有限(通常在1024个以内)。如果考虑性能,poll()也是不合适的,尽管它可以支持的较高的TCP并发数,但是由于其采用“轮询”机制,当并发数较高时,其运行效率相当低,并可能存在I/O事件分派不均,导致部分TCP连接上的I/O出现“饥饿”现象。而如果使用epoll或AIO,则没有上述问题(早期Linux内核的AIO技术实现是通过在内核中为每个 I/O请求创建一个线程来实现的,这种实现机制在高并发TCP连接的情形下使用其实也有严重的性能问题。但在最新的Linux内核中,AIO的实现已经得到改进)。
综上所述,在开发支持高并发TCP连接的Linux应用程序时,应尽量使用epoll或AIO技术来实现并发的TCP连接上的I/O控制,这将为提升程序对高并发TCP连接的支持提供有效的I/O保证。
[10]对一个TCP服务程序可以支持多少并发 TCP 连接进行了严密的讨论,并给出程序测试。我认为这个是正确答案。
一个进程同时打开的文件数目的最大值在实践中是正确的,不符合原题意。
抛开操作系统层面,只考虑 TCP/IP 层面。建立一个 TCP 连接有开销仅仅是三次握手过程中发送一些报文而已。
TCP 连接是虚拟的连接,不是电路连接,维持 TCP 连接理论上不占用网络资源(会占用两头程序的系统资源)。只要连接的双方认为 TCP 连接存在,并且可以互相发送 IP packet,那么 TCP 连接就一直存在。
所以单独谈论“TCP 并发连接数”是没有意义的,因为连接数基本上是要多少有多少。更有意义的性能指标或许是:“每秒钟收发多少条消息”、“每秒钟收发多少字节的数据”、“支持多少个活动的并发客户”等等。
该问题最终答案:
在只考虑 IPv4 的情况下,并发数的理论上限是 2^48(客户端 IP 的上限是 2^32 个,每个客户端IP发起连接的上限是 2^16)。考虑某些 IP 段被保留了,这个上界可适当缩小,但数量级不变。实际的限制是操作系统全局文件描述符的数量,以及内存大小。
1
domain:
type:
protocol:
2
把本地协议地址赋给socket
3
backlog 指定最大允许接入的连接数量。
4
5
6
7
对于于[8]和[9]中的C#版函数如下:
1
2
3
4
5
6 关闭并释放资源
双方都需要两个线程:一个用来接收报文,另一个用来发送报文。我们分别用Threc和Thsend表示
要改成[9]中的多用户模式只需要保持server的监听状态,接着对每个新连接成功的client,存储其配套的socket、Threc、Thsend。
假设有c1、c2、c3三个client连接到server,会建立三个socket:connSocket1,connSocket2,connSocket3
socket为client和server提供endpoint到endpoint的通信。其中endpoint格式为:
三个socket在server端的endpoint相同,在client端的endpoint不同(ip相同,port不同)
所以我们可以用client端的endpoint来标识每个socket。只需要把
2 https://en.wikipedia.org/wiki/User_Datagram_Protocol
3 https://www.quora.com/What-is-the-difference-between-datagrams-and-segments-in-the-TCP-IP-and-OSI-models
4 Error detection and correction
5 /detail/2606156420.html
6 /detail/2522034200.html
7 apue读书笔记之socket
8 https://my.oschina.net/SnifferApache/blog/406563
9 https://my.oschina.net/SnifferApache/blog/413470
10 关于 TCP 并发连接的几个思考题与试验
udp和tcp区别
udp遇见包丢失怎么办,设计一下
udp的包如果出现错误怎么办?上层保证吗
差错检测可以百分百检错吗
有哪些校验和计算方法
TCP如何保证可靠传输、沾包
Linux下高并发socket最大连接数
linux下高性能网络框架,一个服务器连成千上万socket怎么办
RFID项目中服务器需要连多个客户,如何receive消息。
1 UDP和TCP区别
网络层为主机之间提供逻辑通信,运输层为应用进程之间提供端到端的逻辑通信。[1]根据应用程序的不同需求,运输层需要两种协议:
面向连接的TCP(transmission control protocol)协议
无连接的UDP(User datagram protocol)协议
两者区别在于:
UDP是无连接的,TCP是面向连接的
UDP尽最大努力交付报文,TCP保证可靠交付。
UDP是基于报文的,并不合并或拆分上层交下来的报文,而是添加首部后交给IP层。TCP是基于byte流的。
[2]从更多的角度比较:
UDP是message-based无连接协议,也就是发送数据之前不需要建立专用的端到端连接。传输数据的时候也不需要检查接收方的readiness和状态。
1)不保证交付
UDP message发送之后便无法知道其状态了,有可能顺利到达接收方,也可能丢失。UDP没有确认收到、重传、超时这些概念。
2)无序的
3)轻量级,只是在IP的数据报服务之上增加了很少一点功能[1]
4)datagrams
Packets相互独立发送,并且各自有明确的边界。如果发送方一个packet,那接收方一定原样收到。
5)无拥塞控制
UDP本身不提供拥塞控制,如有必要,拥塞控制方法应该在应用层实现。
6)支持广播
而TCP是connection-oriented协议。意味着通信之前必须通过三次握手建立端到端连接。连接建立后,双方都可以通过这个连接发送数据。特点是
1)可靠交付
这里的可靠只限于传输层。在应用层,仍然需要一个独立的acknowledgement flow control。
TCP管理message确认、重传和超时。
这里提到If it gets lost along the way, the server will re-request the lost part.这和[1]中提到可靠传输过程不符:
接收方不需要请求重传某个出错的分组。因为发送方每发完一个分组会设置一个超时计时器,如果超时计时器到期,发送方没有收到接收方对前一个分组的确认。那么发送方会自动重传。
在TCP中只有两种情况:1. 所有数据正确发送 2. 网络已经断掉,超时多次。
2)有序的
3)重量级,支持可靠交付和拥塞控制
4)数据以stream的方式读入。没有message(segment)的明显边界
1.1 辨析data、packet、datagram、message、segment、frame
data的范围最广,什么都可以叫做data,说发送data肯定是不会错的。首先讨论这些名词的联系,他们都可以叫做PDU(protocol data unit)[3],也就是通信协议使用的数据单元。
[1]中使用的是TPDU(transport protocol data unit)。
所以他们的区别在于所在的协议不同。
在传输层叫segment(报文段)
在网络层叫datagram(数据报)
在数据链路层叫frame(帧)
他们可以统称为packet(分组)。
个人认为message和packet同义,比如[3]中这几句可以证明:
But in other cases the term "segment" includes the whole TCP message, including the TCP headers.
A single whole IP message is a "datagram".
The original IP RFC refers to link-layer messages as "packets".
2 包丢失的处理
UDP不保证可靠交付,像拥塞控制一样,如有需要应该由应用层实现。3 差错检测
数据从发送方到接收方可能会产生一些随即错误,差错检测指检测出错误数据[4]。而纠错的方式有两种:
1)Automatic repeat request (ARQ),网络中用的这种。
2)Forward error correction (FEC)
差错检测方式(Error detection schemes)包括:
1 Repetition codes
2 Parity bits
3 Checksums
4 Cyclic redundancy checks (CRCs)
5 Cryptographic hash functions
6 Error-correcting codes
其中checksum是通过某种算术公式把原始数据算出算术和。
CRC是不安全的哈希函数,用来检测数据中随机错误。
UDP和TCP的校验和不仅要对整个IP协议负载(包括UDP/TCP协议头和UDP/TCP协议负载)进行计算,还要先对一个伪协议头进行计算:先要填充伪首部各个字段,然后再将UDP/TCP报头及之后的数据附加到伪首部的后面,再对伪首部使用校验和计算,所得到的值才是UDP/TCP报头部分的校验和。[5]
具体计算方法是:
1)首先把校验和字段清零;
2)然后对每 16 位(2 字节)进行二进制反码求和;
反码求和时,最高位的进位要进到最低位,也就是循环进位。
接收方进行校验:按二进制反码求这些16bit字的和。若不差错,结果应为全1
4 TCP可靠传输
TCP下面的网络提供的是不可靠的传输,所以TCP必须采取适当的措施使得两个运输层之间的通信变得可靠。[1]传输过程可能出现两方面问题:
信道产生差错
接收方来不及处理收到的数据
TCP通过停止等待协议、滑动窗口来规避以上问题。
其中,停止等待协议指每发送完一个包就停止发送,等待对方确认。
停止等待协议的设计采用超时重传机制。
连续ARQ协议是滑动窗口的简化模型。
附:连接建立三次握手,连接释放四次挥手示意图。
5 Linux下高并发socket最大连接数
5.1 限制最大连接数的一些因素,以及去除各种限制的方法。[6]
去除各种限制后,理论上单独一个进程最多可以同时建立60000多个TCP客户端连接。注意,作者server端口范围方面的观点有误,具体见5.2
原文摘要:
1)用户进程可打开文件数限制
在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每个TCP连接都要创建一个socket句柄,每个socket句柄同时也是一个文件句柄)。
$ ulimit -n 1024
这表示当前用户的每个进程最多允许同时打开1024个文件
2)网络内核对TCP连接的有关限制
内核对本地端口号范围的限制(误)
Linux网络内核的
IP_TABLE防火墙对最大跟踪的TCP连接数的限制
3)使用支持高并发网络I/O的编程技术
在Linux上编写高并发TCP连接应用程序时,必须使用合适的网络I/O技术和I/O事件分派机制。
可用的I/O技术有同步I/O,非阻塞式同步I/O(也称反应式I/O),以及异步I/O。
在高TCP并发的情形下,如果使用同步I/O,这会严重阻塞程序的运转,除非为每个TCP连接的I/O创建一个线程。但是,过多的线程又会因系统对线程的调度造成巨大开销。因此,在高TCP并发的情形下使用同步 I/O是不可取的,这时可以考虑使用非阻塞式同步I/O或异步I/O。非阻塞式同步I/O的技术包括使用select(),poll(),epoll等机制。异步I/O的技术就是使用AIO。
从I/O事件分派机制来看,使用select()是不合适的,因为它所支持的并发连接数有限(通常在1024个以内)。如果考虑性能,poll()也是不合适的,尽管它可以支持的较高的TCP并发数,但是由于其采用“轮询”机制,当并发数较高时,其运行效率相当低,并可能存在I/O事件分派不均,导致部分TCP连接上的I/O出现“饥饿”现象。而如果使用epoll或AIO,则没有上述问题(早期Linux内核的AIO技术实现是通过在内核中为每个 I/O请求创建一个线程来实现的,这种实现机制在高并发TCP连接的情形下使用其实也有严重的性能问题。但在最新的Linux内核中,AIO的实现已经得到改进)。
综上所述,在开发支持高并发TCP连接的Linux应用程序时,应尽量使用epoll或AIO技术来实现并发的TCP连接上的I/O控制,这将为提升程序对高并发TCP连接的支持提供有效的I/O保证。
5.2 [6]的错误在于服务端程序只侦听一个端口,并发连接数量与server可用端口数无关
[6]末尾7楼评论也指出了这个错误。标识一条链接是五个部分组成的:[协议,本地ip,本地端口,远端ip,远端端口]。对于服务器而言只用一个端口就可以承载多个链接[10]对一个TCP服务程序可以支持多少并发 TCP 连接进行了严密的讨论,并给出程序测试。我认为这个是正确答案。
一个进程同时打开的文件数目的最大值在实践中是正确的,不符合原题意。
抛开操作系统层面,只考虑 TCP/IP 层面。建立一个 TCP 连接有开销仅仅是三次握手过程中发送一些报文而已。
TCP 连接是虚拟的连接,不是电路连接,维持 TCP 连接理论上不占用网络资源(会占用两头程序的系统资源)。只要连接的双方认为 TCP 连接存在,并且可以互相发送 IP packet,那么 TCP 连接就一直存在。
所以单独谈论“TCP 并发连接数”是没有意义的,因为连接数基本上是要多少有多少。更有意义的性能指标或许是:“每秒钟收发多少条消息”、“每秒钟收发多少字节的数据”、“支持多少个活动的并发客户”等等。
该问题最终答案:
在只考虑 IPv4 的情况下,并发数的理论上限是 2^48(客户端 IP 的上限是 2^32 个,每个客户端IP发起连接的上限是 2^16)。考虑某些 IP 段被保留了,这个上界可适当缩小,但数量级不变。实际的限制是操作系统全局文件描述符的数量,以及内存大小。
6 RFID项目中对多个socket的处理
6.1 一个完整的TCP客户-服务端程序需要的基本socket函数
在APUE中[7],C++版本socket函数如下:1
int socket(int domain, int type, int protocol);
domain:
AF_INET/AF_INET6/AF-UNIX/AF_UPSPEC协议域,又称协议族
type:
SOCK_DGRAM / SOCK_RAW / SOCK_SEQPACKET / SOCK_STREAM规定数据的传输方式
protocol:
IPPROTO_IP/IPPROTO_IPV6/IPPROTO_ICMP/IPPROTO_RAW/IPPROTO_TCP/IPPROTO_UDP指定为因特网域套接字定义的协议,通常为0,自动选择type类型对应的默认协议。
2
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
把本地协议地址赋给socket
3
int listen(int sockfd, int backlog);//only called by server
backlog 指定最大允许接入的连接数量。
4
int connect(int sockfd, const struct sockaddr *addr, socklen_t len);//only called by client
5
int accept(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict len);//only called by server
6
int close(int fg);
7
int shutdown(int sockfd, int howto);
对于于[8]和[9]中的C#版函数如下:
1
Socket(AddressFamily, SocketType, ProtocolType);
2
socketobj.Bind(IPEndPoint);
3
socketobj.Listen(int);
4
socketobj.Connect(IPEndPoint);
5
socketobj.Accept();
6 关闭并释放资源
socketobj.Shutdown(SocketShutdown.Both); socketobj.Close();
6.2 [8]和[9]原理图示
[8]是单用户模式,server只能连一个client,当连接建立后,server便不在监听。双方都需要两个线程:一个用来接收报文,另一个用来发送报文。我们分别用Threc和Thsend表示
要改成[9]中的多用户模式只需要保持server的监听状态,接着对每个新连接成功的client,存储其配套的socket、Threc、Thsend。
假设有c1、c2、c3三个client连接到server,会建立三个socket:connSocket1,connSocket2,connSocket3
socket为client和server提供endpoint到endpoint的通信。其中endpoint格式为:
ip:port。
三个socket在server端的endpoint相同,在client端的endpoint不同(ip相同,port不同)
所以我们可以用client端的endpoint来标识每个socket。只需要把
endpoint作为key,
socket、Threc、Thsend作为value存在字典里面就可以灵活处理每个每个socket连接了。
References
1 谢希仁. 计算机网络2 https://en.wikipedia.org/wiki/User_Datagram_Protocol
3 https://www.quora.com/What-is-the-difference-between-datagrams-and-segments-in-the-TCP-IP-and-OSI-models
4 Error detection and correction
5 /detail/2606156420.html
6 /detail/2522034200.html
7 apue读书笔记之socket
8 https://my.oschina.net/SnifferApache/blog/406563
9 https://my.oschina.net/SnifferApache/blog/413470
10 关于 TCP 并发连接的几个思考题与试验
相关文章推荐
- 黑马程序员--10.网络编程--02.【网络传输三要素在Java中的体现】【TCP和UDP概念】【Socket基本概念】
- IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类
- IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类
- IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类
- Java TCP/UDP socket 编程流程总结
- 网络编程之TCP/UDP及其流程比较
- Java基础---Java---网络编程---TCP、UDP、UDP-键盘录入方式数据、Socket、TCP复制文件、UDP-聊天
- 网络编程之TCP/UDP及其流程比较
- 网络编程之TCP/UDP及其流程比较
- 网络编程之 TCP / UDP 及其流程比较
- iOS 各种网络编程总结--进程、线程、Socket、HTTP、TCP/IP、TCP和UDP
- 网络编程之TCP/UDP及其流程比较
- 网络编程之TCP/UDP及其流程比较
- java网络编程(一) socket方式TCP和Datagram的UDP
- Java TCP/UDP socket 编程流程总结
- java 网络编程【6】 用UDP编写网络聊天程序 以及 TCP编程实例
- 网络编程总结以及TCP与UDP
- Java TCP/UDP socket 编程流程总结
- Java TCP/UDP socket 编程流程总结
- 黑马程序员_学习笔记:15) 网络编程:Socket(udp、tcp)