简介 算法
TCP/IP协议族运行在各类各样的网络媒介上:IEEE 802.3(以太网)和802.5(令牌环)局域网、x.25线路、卫星线路、串行线路。给这些网络中的许多都定义了ip分组的标准格式,可是却没有用于串行线路的标准。SLIP(串行线路IP),目前已经成为事实上的标准,一般用在点对点串行链接上运行TCP/IP。它不是一个互联网标准,这份备忘录的发布不受限制。shell
历史网络
SLIP起源于80年代早期的3COM UNET TCP/IP的实现,它仅仅是一个分组分帧协议:SLIP定义了一系列在串行线路上构造IP分组的字符,仅此而已。它不提供寻址、分组类型识别、错误检测/纠正或者压缩机制。由于这个协议所作的事不多,因此一般很容易实现。函数
大约在1984年,Rick Adams为4.2 Berkeley Unix和Sun Microsystems工做站实现了SLIP而且向世界发布。它很快就因做为一种使用串行线路链接TCP/IP主机和路由器的简单可靠的方法而流行。优化
SLIP一般用在专用串行链路,有时候也用在拨号网络,一般以1.2kbps到19.2kbps的线速被使用。它在主机和路由器混合链接时很是有用(主机-主机、主机-路由器、路由器-路由器都是SLIP网络的通用配置)。编码
可用性.net
SLIP对于大多数基于Berkeley Unix的系统都是可用的,而且被包括进Berkeley发布的4.3BSD标准版。SLIP可用于Ultrix、Sun Unix以及大多数其余衍生于Berkeley的Unix系统。有些终端集线器和IBM PC实现一样支持该协议。设计
Berkeley Unix的SLIP可经过匿名ftp在uunet.uu.net的pub/s1.shar.Z得到,确保经过二进制模式传输该文件,并经过UNIX解压缩程序打开它,把得到的文件做为UNIX的/bin/sh(好比/bin/sh sl.shar)的shell命令使用。ip
协议路由
SLIP协议定义了两个特殊字符:END和ESC。END是八进制的300(十进制192),ESC是八进制的333(十进制的219),不要把它和ASCII的ESCAPE字符混淆,为了讨论方便,ESC表示SLIP的ESC字符。发送分组时,SLIP主机简单地开始发送分组数据。若是一个数据字节和END字符相同,则用两个连续字节ESC和八进制334(十进制220)代替。若是存在和ESC字符相同的字节,则用两个连续字节ESC和八进制335(十进制221)代替。当分组的最后一个分组发送后,跟着发送一个END分组。
Phil Karn建议对算法作一个简单的改变:和分组结尾同样,在开始也加上一个END字符,这样就能清除掉全部线路噪音引发的错误字节。一般状况下,接受者只会看到两个紧挨着的END字符,这样也就产生了一个无效的IP分组。若是SLIP实现没有丢弃这个长度为0的IP分组,IP实现必然会丢弃它。若是存在线路噪音,收到到的由线路噪音产生的数据将会被丢弃,而不会影响后面的分组。
由于没有标准的SLIP规格,也就没有真正定义SLIP分组的最大长度。或许最好接受Berkeley UNIX SLIP驱动使用的最大分组长度:1006字节,包括IP头和传输头(不包括分帧字符)。所以,任何新的SLIP实现应该准备好接收1006字节数据报,而且不能发送超过1006字节的数据报。
缺陷
有一些特性用户但愿SLIP提供而它没有提供。公平地讲,SLIP只是一个好久之前设计的很是简单的协议,那时这些麻烦还不是真正的重要问题。下面是一些对现有SLIP协议通常能看到的肯定:
- 寻址:
为了路由,SLIP链路两端的主机,都须要知道对方的IP地址。另外,当主机拨号链接到路由器时,地址多是动态的,路由器可能须要将ip地址通告拨号主机,SLIP目前没有为主机提供在SLIP连接上传达地址信息的机制。
- 类型识别:
SLIP没有类型字段,所以,在一个SLIP链接上只能运行一个协议,在两台同时运行TCP/IP和DECnet的DEC主机的配置中,不可能在TCP/IP和DECnet之间,用SLIP分享同一条串行线路。SLIP是“串行线路IP”,若是一条串行链接两台多协议计算机,这些计算机能够在这条线路上使用多种协议。
- 错误检测与纠正:
嘈杂的电话线路可能会破坏分组的传输,由于线路速度可能很低(或许2400波特),重传分组的代价很是昂贵。错误检测在SLIP层并不是绝对须要,由于任何IP应用应该检测被破坏的分组(IP头部、UDP和TCP校验和应该足够),可是,一些通用应用程序如NFS一般忽略校验和,依靠网络媒介去检测被破坏的分组。由于重传被线路噪音破坏的分组会花费很长时间,因此若是SLIP能提供某种它本身的简单错误检测机制,那将是很是有效。
- 压缩:
由于拨入线路太慢(一般2400bps),因此,分组压缩能给分组吞吐量带来极大提升。一般,在单独的TCP链接中的分组流,只有少数被改变的IP和TCP头部字段。因此,一个简单的压缩算法就是:只传输头部被改变的部分,而不是整个头部。
为了设计和实现一个SLIP的继任者,不一样的组作了不少工做,也许这个继任者能解决部分或者全部问题。
SLIP驱动程序
下面的C语言函数发送和接收SLIP分组,它们依赖两个函数:send_char()和recv_char(),这两个函数用于在串行线路上发送和接收单个字符。
/* SLIP特殊字符编码
*/
#define END 0300 /* 分组结束标记 */
#define ESC 0333 /* 填充标记 */
#define ESC_END 0334 /* ESC ESC_END表示END数据字段 */
#define ESC_ESC 0335 /* ESC ESC_ESC表示ESC数据字段 */
/* SEND_PACKET:发送长度为len的分组,起始位置为p
*/
void send_packet(p, len)
char *p;
int len; {
/* 发送一个初始END字符,清除全部由于线路噪音而在接受者那里累积的数据
*/
send_char(END);
/* 为分组中的每个字节发送适当的字符序列
*/
while(len--) {
switch(*p) {
/* 若是是一个END字符,咱们发送一个特殊的两字符编码,
* 这样,接收者就不会觉得咱们发送了一个END字符
*/
case END:
send_char(ESC);
send_char(ESC_END);
break;
/* 若是是一个ESC字符,咱们发送一个特殊的两字符编码,
* 这样,接收者就不会觉得咱们发送了一个ESC字符。
*/
case ESC:
send_char(ESC);
send_char(ESC_ESC);
break;
/* 其余状况,直接发送字符
*/
default:
send_char(*p);
}
p++;
}
/* 告诉接收者,咱们完成了一个分组的发送
*/
send_char(END);
}
/* RECV_PACKET:接收一个分组并放入p指向的缓冲区,若是接收的长度大于len,分组将被截断。返回缓冲区中存储的字节的数目
*/
int recv_packet(p, len)
char *p;
int len; {
char c;
int received = 0;
/* 循环读取字节,直到接收完整个分组
* 确保用完缓冲区后再也不复制
*/
while(1) {
/* 取一个字符来处理
*/
c = recv_char();
/* 在须要时处理填充
*/
switch(c) {
/* 若是是END字符,表示分组处理完成
*/
case END:
/* 小优化:若是分组中没有数据,则忽略它。
* 这是为了不用双END字符生成的空分组打扰IP,
* 这些双END字符是为了探测线路噪音。
*/
if(received)
return received;
else
break;
/* 若是是一个ESC字符,等待接收另一个字符,而后推断出将要存入分组的字符
*/
case ESC:
c = recv_char();
/* 若是c不是两个字符中的一个,就违反了协议
* 最好是将这个字符填充进分组 */ switch(c) { case ESC_END: c = END; break; case ESC_ESC: c = ESC; break; } /* 这里是默认处理,直接保存字符 */ default: if(received < len) p[received++] = c; } } }