《TCP/IP详解 卷2:实现》 —1.6 系统调用和库函数
1.6 系统调用和库函数
所有的操作系统都提供服务访问点,程序可以通过它们请求内核中的服务。各种Unix都提供精心定义的有限个内核入口点,即系统调用。我们不能改变系统调用,除非我们有内核的源代码。Unix第7版提供了大约50个系统调用,4.4BSD提供了大约135个,而SVR4大约有120个。
在《Unix程序员手册》第2节中有系统调用接口的文档。它是以C语言定义的,在任何给定的系统中无须考虑系统调用是如何被调用的。
在各种Unix系统中,每个系统调用在标准C函数库中都有一个相同名字的函数。一个应用程序用标准C的调用序列来调用此函数。这个函数再调用相应的内核服务,所使用的技术依赖于所在系统。例如,函数可能把一个或多个C参数放到通用寄存器中,并执行几条机器指令产生一个软件中断进入内核。对于我们来说,可以把系统调用看成C函数。
在《Unix程序员手册》的第3节中为程序员定义了一般用途的函数。虽然这些函数可能调用一个或多个内核系统调用,但没有进入内核的入口点。如函数printf可能调用了系统调用write去执行输出,而函数strcpy(复制一个串)和atoi(将ASCII码转换成整数)完全不涉及操作系统。
从实现者的角度来看,系统调用和库函数有着根本的区别,但在用户看来区别并不大。例如,在4.4BSD中我们运行图1-2中的程序。程序调用了3个函数—socket、sendto和recvfrom,每个函数最终调用了内核中一个同样名称的函数。在本书的后面我们可以看到这3个系统调用的BSD内核实现。
如果我们在SVR4中运行这个程序,在那里,用户库中的插口函数调用“流”子系统,那么3个函数同内核的相互作用是完全不同的。在SVR4中对socket的调用最终会调用内核的 open系统调用,操作文件/dev/udp并将流模块sockmod放置到结果流。调用sendto导致一个putmsg系统调用,而调用recvfrom导致一个getmsg系统调用。这些SVR4的细节在本书中并不重要,我们仅仅想指出的是:实现可能不同但都提供相同的API给应用程序。
最后,从一个版本到下一个版本的实现技术可能会改变。例如,在Net/1中,send和sendto是分别用内核系统调用实现的。但在Net/3中,send是一个调用系统调用sendto的库函数:
send(int s, char *msg, int len, int flags)
{
return(sendto(s, msg, len, flags, (struct sockaddr *) NULL, 0));
}
用库函数实现send的好处是仅调用sendto,减少了系统调用的个数和内核代码的长度;缺点是由于多调用了一个函数,增加了进程调用send的开销。
因为本书是说明TCP/IP的伯克利实现,所以大多数进程调用的函数(socket、bind、connect等)是直接由内核系统调用来实现的。
- 点赞
- 收藏
- 关注作者
评论(0)