III. 环境
我们假定, 典型的主机会有一个分时操作系统, CPU 由各进程共享。
进程
我们设想每个进程都带有一个用户号标签。可能有多个进程具有相同的用户号, 如果是这样, 它们在使用网络方面应当相互协作。
我们设想每个进程都包含一组为该进程所独有的端口。这些端口用于进程的输入或输出, 数据来自或去往文件、设备或其他进程。
我们还设想每个进程都有一个事件通道, 通过它可以接收非常短的消息 (几个比特)。我们将用这一机制来通知进程, 在它之外发生了某个动作。
为了参与网络活动, 进程把一个本地 socket 连接到它的某个端口上。socket 由用户号、主机和 AEN 来标识, 如果一个 socket 与一个进程的用户号相同且位于同一台主机中, 那么该 socket 对该进程而言就是本地的。进程在引用本地 socket 时只需指定 AEN。
每个端口都有一个状态, 该状态会被系统调用以及进程外部的并发事件修改。每当某个端口的状态发生变化时, 就会通过进程的事件通道向它发送一个事件, 指明是哪个端口的状态发生了变化。随后进程可以查看该端口的状态。
下文的描述性材料用到了这些假设。不过, 这些假设并非网络协议所强加的, 第 IV 节所建议的实现也绝无约束力。
我们希望讲得非常清楚: 提供这些材料只是为了提示实现中可能会遇到哪些困难, 而不是要强加任何特定的规范。
例如, 我们把到达未连接的本地 socket 的 <RFC> 视为合法的并将其排队。如果需要, NCP 也可以像 Meyer 建议的那样拒绝它们, 或者把它们保留一段时间, 如果不能很快得到满足再予以拒绝。所提出的协议支持所有这些选择。
另一个本地选择就是前面提到的把多个端口连接到一个 socket 上。我们展示的是一一对应, 但这一点可以不予理会。同样, 这些系统调用也仅仅是示意性的。
系统调用
下面是用户进程可能执行的一些典型系统调用。我们列出它们只是为了完整起见; 每个站点无疑都会实现任何方便的等价集合。
我们使用如下记法
Syscall ( arg , arg ...; val ... )
1 2 1
其中
-
Syscall 是系统调用
-
arg₁ 等是随调用提供的参数, 而
-
val₁ 等是系统调用返回的值。
Init (P,AEN,FS,Bsiz;C)
-
P: 指定进程的一个端口。
-
AEN: 指定一个本地 socket。本进程的用户号和本主机的主机号是隐含的。
-
FS: 指定任意主机中具有任意用户号、任意 AEN 的一个 socket。
-
Bsiz: 指定用户想要用于缓冲消息的存储量, 以比特为单位。
-
C: 返回的条件码。
Init 尝试把由 AEN 指定的本地 socket 连接到端口 P 上, 并发起与 socket FS 的连接。C 可能的返回值有
-
C = ok: 该 Init 合法, 正在联系 socket FS。当连接建立或者 FS 拒绝时, 进程将收到一个事件。
-
C = busy: 该本地 socket 正被本进程或具有相同用户号的其他某个进程的一个端口使用。未采取任何动作。
-
C = homosex: AEN 和 FS 同为发送 socket 或同为接收 socket。
-
C = nohost: FS 中指定的主机未知。
-
C = bufbig: Bsiz 过大。
Listen (P,AEN,Bsize;C)
-
P: 指定进程的一个端口。
-
AEN: 指定一个本地 socket。
-
Bsiz: 指定缓冲区大小。
-
C: 返回的合法性代码。
C 的代码有
C = ok
C = busy
C = bufbig
由 AEN 指定的本地 socket 被连接到 P 上。如果有等待中的呼叫, 就处理它; 否则不采取任何动作。当有呼叫到来时, 将建立一条连接, 并通过一个事件通知进程。
Close (P)
P 指定进程的一个端口。
所有活动都被停止, 该端口变为空闲, 可作他用。
Transmit (P,M,L1;L2,C)
-
P: 指定具有一条打开连接的端口。
-
M: 要传输的文本。
-
L1: 指定文本的长度。
-
L2: 实际传输的长度。
-
C: 错误码。
在端口两侧的进程之间进行传输。
C 的代码有
C = ok
或
- C = not open: 当前没有打开的连接, 且其他方面未被禁止
Status (P;C)
端口 P 的状态以 C 的形式返回。