杜曉春,劉婉妮,王 宏
(西安歐亞學院,710065)
TCP/IP協議(Transmission Control Protocol/Internet Protocol),是Internet最基本的協議,也是Internet的基礎。它并不是只包括TCP(傳輸控制協議)和IP(網際協議)這兩個協議,而是支持互聯網運行的一套協議的總稱,因此TCP/IP協議又被稱為TCP/IP協議簇。
TCP/IP是一種分層協議,它由多個交互的模塊構成,每個模塊都提供了特定的功能,而這些模塊并不是必須相互依存的。也就是說,TCP/IP協議簇中的每一層中都包含一些相對獨立的協議,可以根據需要將這些協議進行混合使用。從協議分層模型的角度來說,TCP/IP協議可以分為四層,它包括:網絡接口層、網絡層、傳輸層以及應用層。其中,應用層協議是TCP/IP協議簇與主機上應用程序或進程接口的地方,因此又被稱為處理層。在這一層上定義了對進程或應用程序的用戶接口,此時TCP/IP也因為應用層是直接為用戶提供服務的,所以應用層上的協議大家也接觸的最多。比如訪問Web頁面所用到的HTTP協議,遠程登錄所用到的Telnet協議,傳輸文件所用到的FTP協議以及發送郵件所用到的SMTP協議等等。在這里,TCP/IP協議與服務之間發生了重疊。每一個TCP/IP服務都有一個相應的端口地址,用以識別特定的進程和服務。
我們可以通過網絡編程的方式來實現這些網絡協議,目前較為流行的網絡編程模型是客戶端/服務器模式(C/S)。在通信的雙方中,作為客戶端的一方在需要獲得服務時向服務器端提出申請,另一方作為服務器會處理客戶提出的請求并進行相應的響應。服務器需要保證進程始終運行,同時它還需要監聽網絡端口狀態,一旦有客戶請求到來它就要及時的啟動一個服務進程來響應該客戶,同時繼續監聽端口狀態。
在這里,我們通過Telnet協議和FTP協議舉例說明如何運用C++語言進行網絡編程從而實現相應的網絡協議。當用戶使用Telnet命令進行遠程登錄時首先得滿足以下條件:在本地主機上必須要安裝Telnet的客戶端程序,必須要知道遠程主機或服務器的IP地址或者域名,還必須要知道登錄用的賬戶名與密碼。我們可以把Telnet遠程登錄服務分解成以下四個工作過程:
(1)本地主機與遠程主機之間連接的建立。該過程其實是建立了一個TCP的連接;
(2)將本地主機上用戶輸入標識與口令及其用戶以后輸入的任何的命令或者字符用NVT的格式傳送到遠程服務器或主機。該過程事實上是本地主機向遠程主機發送一個IP數據報;
(3)將遠程主機發送的NVT格式的數據轉化為本地主機所能夠接受的格式,并把它發送給本地終端,其中包括了輸入命令的回顯以及執行的結果;
(4)最后,本地主機和遠程主機進行連接的撤除,這是一個撤除TCP連接的過程。
數據信息是被用戶從鍵盤上輸入并通過系統傳到客戶機程序的,此程序將其處理后返回給操作系統,并由系統傳送給遠地主機,遠地主機則把接收到的數據傳送到服務器程序,經過服務器端程序處理后傳給操作系統中的偽終端入口點,最后,遠地的操作系統會將數據傳送給用戶正在使用的應用程序,這就是一次完整輸入的過程;輸出則是從相同的通道從服務器端傳送到客戶端。
根據Telnet的工作過程,我們進行C++編程,并且采用了Winsock網絡編程技術,了Winsock是當今最流行的網絡通信的接口,其接口具有開發、套接字規范和支持多種協議等特點,這使得計算機之間的通信與文件的傳輸更加方便、安全。部分代碼如下所示:
CHostDialog host;
host.DoModal();
cHostName = host.m_HostName; //顯示選擇登錄的Telnet服務器對話框
BOOL bOK; //創建套接字,并連接服務器
cSock = new CClientSocket(this);
if(cSock != NULL)
{bOK = cSock->Create();
if(bOK == TRUE)
{//設置在該套接字上欲接收的消息
cSock->AsyncSelect(FD_READ | FD_WRITE | FD_CLOSE| FD_CONNECT | FD_OOB);
cSock->Connect(cHostName,23);
//建立連接
GetDocument()->SetTitle(cHostName);
Sleep(90); //等待}
else
{ASSERT(FALSE);
delete cSock;
cSock = NULL; }}
else
{ AfxMessageBox("Could not create new socket",MB_OK);}}
雖然Telnet給我們提供了很多方便,但其在安全方面存在的問題也是不容忽視的。盡管它要求用戶輸入登錄所用的賬戶名與密碼,但僅僅這些是不夠的,凡是連接在因特網上的主機都可以很容易的使用嗅探器來竊取賬戶名與密碼。正因為如此,Telnet的安全實現即Stelnet正變得越來越被重視,這些實現是使用的安全套接字層SSL(Secure Sockets Layer)的接口加密了Telnet客戶端與服務器端之間的數據流量,從而避免在網絡上泄漏了Telnet的安全標識與口令。如果我們需要使用Telnet服務,那么我們就有必要使用Telnet的安全實現。
另外,在使用FTP服務時,FTP和主機之間建立了兩條連接。一條用來傳送數據(端口號20);一條用來傳送控制信息(端口號21)。FTP協議的這種把命令與控制信息分開的傳輸方式使得其效率更高。控制鏈路使用極其簡單的通信規則,在其上面傳送的只是每次一行的命令或者響應信息;另一方面,數據的傳送則需要比控制信息的傳送更加復雜的規則,因為要傳送的數據的類型也是極其復雜的。而FTP數據連接的建立總共需要三個步驟:
客戶端使用一個臨時的端口發出被動打開的命令,這必須是由客戶端來做的,因為是客戶端發出的文件傳送的命令的;
在客戶端則使用PORT命令把此臨時端口號傳送到服務器端;
服務器端在收到這個端口號后,使用20號端口與此臨時端口號立即發出主動打開命令。
FTP的實現過程中的部分代碼如下所示:
m_Ctrlsok = socket(AF_INET,SOCK_STREAM,0);
//建立套接字失敗,則返回false
if (m_Ctrlsok == SOCKET_ERROR)
{ nRet = closesocket(m_Ctrlsok);
::WSACleanup();
return FALSE; }
//定義結構體sockaddr_in,用于設置地址信息。
struct sockaddr_in sockAddr;
//將一個點間隔地址轉換成一個in_addr
sockAddr.sin_addr.S_un.S_addr=inet_addr(serverhost.GetBuffer(serverhost.GetLength()));
//設置協議簇,在socket編程中只能是AF_INET
sockAddr.sin_family=AF_INET;
//將主機的無符號短整型數轉換成網絡字節順序
sockAddr.sin_port=htons(serverport);
//連接服務器
if(0!=(connect(m_Ctrlsok,(sockaddr*)&sockAddr,sizeof(sockAddr))))
{ return FALSE;}
FTP協議在最初的設計時,它的安全性并不是一個非常嚴重的問題。雖然FTP的連接是需要口令與密碼的,但是它的密碼是以明文形式發送的,并沒有進行加密。攻擊者可以很容易的截取到這些信息。同時,數據的傳送也是以明文的方式進行的,這是極不安全的。要解決這些問題,就必須在FTP的應用層與TCP的應用層間加入安全套接層,即有SSL_FTP。
隨著網絡的普及面越來越廣,網絡應用的日益深入,TCP/IP協議作為網絡通信的基礎協議將會被越來越多的人所了解、掌握。人們對TCP/IP應用層協議的了解也將越來越深入。
[1]Behrouz A.Forouzan 著,王海等譯,《TCP/IP 協議族》[M],清華大學出版社,2011年1月。
[2]Laura A.Chappell Ed Tittel 著,張長富等譯,《TCP/IP協議原理與應用(第3版)》[M],清華大學出版社,2009年11月。
[3]W.Richard Stevens著,范建華等譯《TCP/IP詳解卷1:協議》[M],機械工業出版社,2000年4月。
[4]Gary R.Wright、 W.Richard Stevens著,陸雪瑩等譯,《TCP/IP詳解卷2:實現》[M],機械工業出版社,2004年1月。