簡介 算法
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; } } }