套接字API是软件中最普遍、最持久的接口之一。socket API由加州大学伯克利分校的计算机系统研究小组开发,1982年首次作为4.1 BSD操作系统的一部分发布。虽然有更长寿的API,例如,那些处理Unix文件I/Oit的API是相当令人印象深刻的,因为一个API已经使用了27年,基本上没有改变。套接字API的唯一重大更新是辅助例程的扩展,以适应IPv6使用的更大的地址。2
自套接字API首次开发以来,Internet和网络世界总体上发生了非常显著的变化,但在许多方面,API缩小了开发人员思考和编写网络应用程序的方式。本文简要介绍了开发套接字API时出现的一些条件,并考虑了这些条件如何影响了网络代码的编写方式。稍后,我将介绍开发人员如何尝试绕过API中的一些固有限制,并在不断变化的网络世界中处理套接字的未来。
1982年和2009年的网络最大的两个区别是拓扑和速度。在很大程度上,人们注意到的是速度的提高,而不是拓扑结构的变化。1982年,商用长途网络链路的最大带宽为1.5Mbps。同时部署的以太网局域网的速度为10Mbps。一个家庭用户——很少这样的人——幸运地通过电话线连接到任何计算设备,速度为300bps。局域网中两台机器之间的往返时间以几十毫秒计算,Internet上的系统之间的往返时间以几百毫秒计算,这当然取决于位置和在机器之间路由数据包时所经过的跳数。(早期的互联网见第52页。)
当时的网络拓扑结构相对简单。大多数计算机只连接到一个局域网;该局域网连接到一个原始路由器,该路由器可能与其他局域网有几个连接,与Internet只有一个连接。对于一个应用程序到另一个应用程序,连接要么通过局域网,要么通过一个或多个路由器(称为imp (Internet消息传递))进行。
套接字API最普及的分布式编程模型是客户机/服务器模型,其中有一个服务器和一组客户机。客户端向服务器发送消息,要求服务器代表它们完成工作,等待服务器完成所请求的工作,并在稍后的某个时刻接收应答。这种计算模型现在是如此普遍,它常常是许多软件工程师所熟悉的唯一模型。当时设计,然而,它被视为一种扩展Unix文件I / O模型在计算机网络。另一个因素集中的套接字API客户机/服务器模型是最受欢迎的是TCP协议支持,具有固有的1:1通信模型。
套接字API使客户机/服务器模型易于实现,因为程序员需要将少量额外的系统调用添加到他们的非网络代码中,这样就可以利用其他计算资源。虽然也有其他的模型,但是有了套接字API,客户端/服务器模型将主导网络计算。
尽管套接字API比中显示的有更多的入口点表1,这五个是API的核心,也是它与常规文件I/O的区别所在。在现实中,套接字()
呼叫可能被删除了,被替换成open ()
,但当时并没有这样做。的套接字()
而且open ()
调用实际上向程序返回相同的东西:一个进程惟一的文件描述符,在API的所有后续操作中使用它。正是API的简单性导致了它的普及,但这种普及阻碍了替代API或增强API的开发,而这些API可以帮助程序员开发其他类型的分布式程序。
客户机/服务器计算在开发之初具有许多优点。它允许许多用户共享资源,如大型存储阵列和昂贵的打印设备,同时将这些设备置于曾经运行大型主机计算设施的相同部门的控制之下。有了这种共享模式,就有可能提高那些在当时非常昂贵的资源的利用率。
套接字API没有很好地服务三个完全不同的网络领域:低延迟或实时应用程序;高带宽应用程序;还有多家系统,也就是那些有多个网络接口的系统。很多人混淆了增加网络带宽和更高的性能,但增加带宽并不一定减少延迟。套接字API面临的挑战是如何让应用程序更快地访问网络数据。
任何使用套接字API的程序发送和接收数据的方式都是通过调用操作系统。所有这些调用都有一个共同点:调用程序必须反复请求数据被传递。在客户机/服务器计算的世界中,这些恒定的请求非常有意义,因为没有客户机的请求,服务器就不能做任何事情。打印服务器调用客户端没有什么意义,除非客户端有它希望打印的东西。但是,如果提供的服务是音乐或视频分发呢?在媒体分发服务中,可能有一个或多个数据源和许多侦听器。只要用户在收听或观看媒体,最可能的情况是应用程序将需要到达的任何数据。特别地请求新数据是对应用程序的时间和资源的浪费。套接字API没有为程序员提供一种方式,让他们能够说:“只要有我的数据,就直接调用我来处理它。”
相反,套接字程序是从缺乏而不是大量数据的角度编写的。网络程序非常习惯于等待数据,所以它们使用单独的系统调用,套接字()
,这样他们就可以监听多个数据源,而不会阻塞单个请求。基于套接字的程序的典型处理循环并不简单read()、过程()、read ()
,而是Select (), read(), process(), Select ()
.虽然向循环添加单个系统调用似乎不会增加太多负担,但事实并非如此。每个系统调用都需要封送参数并将其复制到内核中,同时也会导致系统阻塞调用进程并安排另一个调用进程。如果调用时调用方有可用的数据select ()
,那么所有跨越用户/内核边界的工作都被浪费了,因为aread ()
会立即返回数据。不断的检查/读取/检查是浪费的,除非连续请求之间的时间间隔相当长。
套接字程序是从缺乏而不是大量数据的角度编写的。
解决这个问题需要反转应用程序和操作系统之间的通信模型。人们提出了各种各样的尝试,希望提供一种允许内核直接调用程序的API,但由于一些原因,没有一种获得了广泛的接受。在开发套接字API时存在的操作系统,除了非常深奥的情况外,都是单线程的,在单处理器计算机上执行。如果内核安装了向上调用API,那么就会出现调用可以在哪个上下文中执行的问题。因为内核正在执行对应用程序的向上调用而暂停系统上的所有其他工作,这是不可接受的,特别是在拥有数十到数百个用户的分时系统中。这种软件架构唯一流行的地方是嵌入式系统和网络路由器,那里没有用户,也没有虚拟内存。
虚拟内存的问题使实现内核向上调用机制的问题更加复杂。分配给用户进程的内存是虚拟内存,而网络接口等设备使用的内存是物理内存。让内核将物理内存从设备映射到用户空间程序破坏了虚拟内存系统提供的基本保护之一。
为了克服套接字API中存在的性能问题,已经提出了一些不同的机制,有时还在各种操作系统上实现了这些机制。其中一个机制是零拷贝的套接字。任何使用过网络堆栈的人都知道,复制数据会破坏网络协议的性能。因此,为了提高对高带宽比对低延迟更感兴趣的网络应用程序的速度,操作系统被修改为删除尽可能多的数据副本。传统上,操作系统对系统接收到的每个包执行两个副本。第一次复制是由网络驱动程序从网络设备的内存执行到内核的内存中,第二次复制是在用户程序读取数据时由内核中的套接字层执行的。这些复制操作的开销很大,因为对于系统接收到的每条消息都必须进行复制操作。类似地,当程序想要发送消息时,每发送一条消息,数据都必须从用户的程序复制到内核中;然后,数据将被复制到缓冲区中,由设备用于在网络上传输数据。
大多数操作系统设计人员和开发人员都知道,数据复制是对系统性能的诅咒,并努力减少这种复制在内核中。内核避免数据复制的最简单方法是让设备驱动程序直接将数据复制到内核内存中或从内核内存中复制出去。在现代网络设备上,这是它们如何构造内存的结果。驱动程序和内核共享两组数据包描述符,一个用于发送,一个用于接收,每个描述符都有一个指向内存的指针。网络设备驱动程序最初用内核的内存填充这些环。当接收到数据时,设备在正确的接收描述符中设置一个标志,并通常通过中断告诉内核有数据在等待它。然后,内核从接收描述符环中删除已填充的缓冲区,并将其替换为设备要填充的新缓冲区。数据包以缓冲区的形式在网络堆栈中移动,直到到达套接字层,也就是它所在的位置复制当用户的程序调用时read ()
.程序发送的数据由内核以类似的方式处理,内核缓冲区最终被添加到传输描述符环,然后设置一个标志来告诉设备,它可以将数据放在网络上的缓冲区中。
内核中的所有这些工作都没有解决最后的复制问题,已经进行了多次尝试来扩展套接字API以删除这个复制操作。1,3.问题仍然是如何跨用户/内核边界安全地共享内存。内核不能把它的内存交给用户程序,因为这时它就失去了对内存的控制。用户程序崩溃可能会使内核失去大量可用内存,导致系统性能下降。跨内核/用户边界共享内存缓冲区也存在固有的安全问题。对于用户程序如何使用套接字API实现更高的带宽,没有单一的答案。
对于那些更关心延迟而不是带宽的程序员来说,他们所做的就更少了。对于等待网络事件的程序来说,唯一的显著改进是增加了一组程序可以等待的内核事件。内核的事件,或kevents ()
的延伸select ()
包含内核可能告诉程序的任何可能事件的机制。在kevents出现之前,用户程序可以调用select ()
在任何文件描述符上,这将让程序知道一组文件描述符中的任何一个是可读、可写的或出现错误的。当程序被编写成一个循环并等待一组文件描述符时,例如,从网络读取并写入磁盘select ()
调用就足够了,但一旦程序想要检查其他事件,比如计时器和信号,select ()
不再担任。低延迟应用的问题在于kevents ()
不交付数据;它们只传递数据准备好了的信号,就像select ()
叫了。下一个合乎逻辑的步骤将是拥有一个基于事件的API,它也可以交付数据。没有理由让应用程序两次跨越用户/内核边界,仅仅为了获得内核知道应用程序需要的数据。
套接字API不仅提供了对应用程序性能问题的作家,也是缩小的沟通的类型。客户机/服务器范式本质上是一种1:1类型的通信。尽管服务器可以处理来自不同客户机组的请求,但对于一个请求或一组请求,每个客户机只有到单个服务器的一个连接。在一个每台计算机只有一个网络接口的世界里,这种范式是完全有意义的。客户端和服务器之间的连接由<源IP、源端口、目的IP、目的端口>的四元素标识。由于服务通常有一个众所周知的目的端口(例如,HTTP为80),惟一容易变化的值是源端口,因为IP地址是固定的。
在1982年的Internet中,除了路由器之外的每台机器都只有一个网络接口,这意味着要识别一个服务,比如远程打印机,客户端计算机需要一个目的地址和端口,而客户端计算机本身也只有一个源地址和端口。虽然它确实存在,但计算机可能有多种方式获得服务的想法太复杂,实现起来也太昂贵。考虑到这些约束,套接字API就没有理由向程序员公开编写多家程序的能力——可以管理哪些接口或连接对它重要。当这些特性被实现时,它们是操作系统内路由软件的一部分。程序访问它们的唯一途径是通过一组叫做路由套接字的晦涩的非标准内核api。
在一个有多个网络接口的系统上,使用标准的套接字API是不可能编写一个容易多家的应用程序的,也就是说,利用两个接口,即使其中一个发生故障,或者如果信息包经过的主要路由中断,应用程序也不会失去与服务器的连接。
最近开发的流控制传输协议(SCTP)4在协议级别集成了对多宿主的支持,但是不可能通过套接字API导出这种支持。最初提供了几个专门的系统调用,这是访问此功能的唯一方法。目前,这是唯一一个同时具备该特性的容量和用户需求的协议,因此该API还没有跨多个操作系统进行标准化。表2显示了SCTP添加的api。
函数的列表表2包含了比严格需要的更多的api,重要的是要注意,许多是先前存在的api的派生,例如send ()
这需要扩展到在多户家庭的世界中工作。需要对api集进行协调,使多主机在套接字世界中成为一流的公民。现在的问题是套接字是如此的成功和普遍,以至于要改变现有的API集是非常困难的,因为担心会混淆它的用户或先前存在的使用它的程序。
随着系统内建了更多的网络接口,提供编写利用多主机的应用程序的能力将是绝对必要的。人们可以很容易地想象这种技术在智能手机上的应用,它已经有三个网络接口:通过蜂窝网络的主要连接,一个WiFi接口,通常还有一个蓝牙接口。即使这些网络接口中的一个正常工作,应用程序也没有理由失去连通性。应用程序设计人员面临的问题是,他们希望自己的代码能够在大量的设备(从手机、笔记本电脑到台式机等等)上工作,很少或不做任何更改。通过正确定义api,我们可以消除阻止这一过程的人为障碍。只是因为套接字API的历史,以及到目前为止它已经“足够好”的事实,这一需求尚未得到解决。
随着系统内建了更多的网络接口,提供编写利用多主机的应用程序的能力将是绝对必要的。
高带宽、低延迟和多归属正在推动套接字API的替代方案的开发。随着局域网现在达到10Gbps,很明显,对于许多应用程序来说,客户机/服务器风格的通信效率太低,无法使用可用的带宽。通信模式支持的套接字API必须扩展到允许在内核内存共享边界,以及转型机制提供数据的应用程序。多归属必须成为套接字API的一流特性,因为具有多个活动接口的设备现在正成为网络系统的标准。
Q有关文章queue.acm.org
代码洞穴:探索洞穴般的代码基础
乔治Neville-Neil
http://queue.acm.org/detail.cfm?id=945136
API设计问题
Michi亨宁
http://queue.acm.org/detail.cfm?id=1255422
你对网络性能一无所知
凯文·福尔和史蒂夫·麦卡恩
http://queue.acm.org/detail.cfm?id=1066069
1.巴拉吉,P.,巴格瓦特,S.,金,h - w。,而且Panda, D.K. Asynchronous zero-copy communication for synchronous sockets in the sockets direct protocol (sdp) over infiniband journal. In第20届IEEE国际并行与分布式处理研讨会论文集。
2.Gilligan, R., Thomson, S., Bound, J., McCann, J.和Stevens, W. IPv6的基本套接字接口扩展。RFC 3493(2003年2月);http://www.rfc-editor.org/rfc/rfc3493.txt.
3.Romanow, A., Mogul, J., Talpey, T.和Bailey, S. IP上的远程直接内存访问(RDMA)问题声明。RFC 4297(2005年12月);http://www.rfc-editor.org/rfc/rfc4297.txt.
4.斯图尔特,R.等人。流控制传输协议。RFC 2960(2000年10月);http://www.ietf.org/rfc/rfc2960.txt.
©2009 acm 0001-0782/09/0600 $10.00
允许为个人或课堂使用本作品的全部或部分制作数字或硬拷贝,但不得为盈利或商业利益而复制或分发,且副本在首页上附有本通知和完整的引用。以其他方式复制、重新发布、在服务器上发布或重新分发到列表,需要事先获得特定的许可和/或付费。
数字图书馆是由计算机协会出版的。版权所有©2009 ACM, Inc.