套接字

套接字

套接字是一種通信機制,憑藉這種機制,客戶/伺服器系統的開發工作既可以在本地單機上進行,也可以跨網路進行,Linux所提供的功能(如列印服務,ftp等)通常都是通過套接字來進行通信的,套接字的創建和使用與管道是有區別的,因為套接字明確地將客戶和伺服器區分出來,套接字可以實現將多個客戶連線到一個伺服器。

基本信息

簡介

套接字套接字
套接字,也稱為BSD套接字,是支持TCP/IP的網路通信的基本操作單元,可以看做是不同主機之間的進程進行雙向通信的端點,簡單的說就是通信的兩方的一種約定,用套接字中的相關函式來完成通信過程。套用層通過傳輸層進行數據通信時,TCP和UDP會遇到同時為多個應用程式進程提供並發服務的問題。

簡單的舉例說明:Socket=Ipaddress+TCP/UDP+port。

具體流程

套接字套接字
1、創建套接字――socket()
功能:使用前創建一個新的套接字
格式:SOCKETPASCALFARsocket(intaf,inttype,intprocotol);
參數:af:通信發生的區域
type:要建立的套接字類型
procotol:使用的特定協定
2、指定本地地址――bind()
功能:將套接字地址與所創建的套接字號聯繫起來。格式:intPASCALFARbind(SOCKETs,conststructsockaddrFAR*name,intnamelen);
參數:s:是由socket()調用返回的並且未作連線的套接字描述符(套接字號)。
其它:沒有錯誤,bind()返回0,否則SOCKET_ERROR。3、建立套接字連線――connect()和accept()
功能:共同完成連線工作
格式:intPASCALFARconnect(SOCKETs,conststructsockaddrFAR*name,intnamelen);
SOCKETPASCALFARaccept(SOCKETs,structsockaddrFAR*name,intFAR*addrlen);
參數:同上
4、監聽連線――listen()
功能:用於面向連線伺服器,表明它願意接收連線。
格式:intPASCALFARlisten(SOCKETs,intbacklog);
5、數據傳輸――send()與recv()
功能:數據的傳送與接收
格式:intPASCALFARsend(SOCKETs,constcharFAR*buf,intlen,intflags);
intPASCALFARrecv(SOCKETs,constcharFAR*buf,intlen,intflags);
參數:buf:指向存有傳輸數據的緩衝區的指針
6、多路復用――select()
功能:用來檢測一個或多個套接字狀態。
格式:intPASCALFARselect(intnfds,fd_setFAR*readfds,fd_setFAR*writefds,
fd_setFAR*exceptfds,conststructtimevalFAR*timeout);
參數:readfds:指向要做讀檢測的指針
writefds:指向要做寫檢測的指針
exceptfds:指向要檢測是否出錯的指針
timeout:最大等待時間
7、關閉套接字――closesocket()
功能:關閉套接字s
格式:BOOLPASCALFARclosesocket(SOCKETs);

基本分類

套接字套接字
常用的TCP/IP協定的3種套接字類型如下所示。
流套接字(SOCK_STREAM):
流套接字用於提供面向連線、可靠的數據傳輸服務。該服務將保證數據能夠實現無差錯、無重複傳送,並按順序接收。流套接字之所以能夠實現可靠的數據服務,原因在於其使用了傳輸控制協定,即TCP(TheTransmissionControlProtocol)協定。
數據報套接字(SOCK_DGRAM):
數據報套接字提供了一種無連線的服務。該服務並不能保證數據傳輸的可靠性,數據有可能在傳輸過程中丟失或出現數據重複,且無法保證順序地接收到數據。數據報套接字使用UDP(UserDatagramProtocol)協定進行數據的傳輸。由於數據報套接字不能保證數據傳輸的可靠性,對於有可能出現的數據丟失情況,需要在程式中做相應的處理。
原始套接字(SOCK_RAW)
原始套接字(SOCKET_RAW)允許對較低層次的協定直接訪問,比如IP、ICMP協定,它常用於檢驗新的協定實現,或者訪問現有服務中配置的新設備,因為RAWSOCKET可以自如地控制Windows下的多種協定,能夠對網路底層的傳輸機制進行控制,所以可以套用原始套接字來操縱網路層和傳輸層套用。比如,我們可以通過RAWSOCKET來接收發向本機的ICMP、IGMP協定包,或者接收TCP/IP棧不能夠處理的IP包,也可以用來傳送一些自定包頭或自定協定的IP包。網路監聽技術很大程度上依賴於SOCKET_RAW
原始套接字與標準套接字(標準套接字指的是前面介紹的流套接字和數據報套接字)的區別在於:原始套接字可以讀寫核心沒有處理的IP數據包,而流套接字只能讀取TCP協定的數據,數據報套接字只能讀取UDP協定的數據。因此,如果要訪問其他協定傳送數據必須使用原始套接字。

主要參數

套接字套接字
區分不同應用程式進程間的網路通信和連線,主要有3個參數:通信的目的IP位址、使用的傳輸層協定(TCP或UDP)和使用的連線埠號。Socket原意是“插座”。通過將這3個參數結合起來,與一個“插座”Socket綁定,套用層就可以和傳輸層通過套接字接口,區分來自不同應用程式進程或網路連線的通信,實現數據傳輸的並發服務。
Socket可以看成在兩個程式進行通訊連線中的一個端點,是連線應用程式和網路驅動程式的橋樑,Socket在應用程式中創建,通過綁定與網路驅動建立關係。此後,應用程式送給Socket的數據,由Socket交給網路驅動程式向網路上傳送出去。計算機從網路上收到與該Socket綁定IP位址和連線埠號相關的數據後,由網路驅動程式交給Socket,應用程式便可從該Socket中提取接收到的數據,網路應用程式就是這樣通過Socket進行數據的傳送與接收的。

分類介紹

HostA上的程式A將一段信息寫入Socket中,Socket的內容被HostA的網路管理軟體訪問,並將這段信息通過HostA的網路接口卡傳送到HostB,HostB的網路接口卡接收到這段信息後,傳送給HostB的網路管理軟體,網路管理軟體將這段信息保存在HostB的Socket中,然後程式B才能在Socket中閱讀這段信息。
假設在網路中添加第三個主機HostC,那么HostA怎么知道信息被正確傳送到HostB而不是被傳送到HostC中了呢?基於TCP/IP網路中的每一個主機均被賦予了一個唯一的IP位址,IP位址是一個32位的無符號整數,由於沒有轉變成二進制,因此通常以小數點分隔,如:198.163.227.6,正如所見IP位址均由四個部分組成,每個部分的範圍都是0-255,以表示8位地址。
值得注意的是IP位址都是32位地址,這是IP協定版本4(簡稱Ipv4)規定的,目前由於IPv4地址已近耗盡,所以IPv6地址正逐漸代替Ipv4地址,Ipv6地址則是128位無符號整數。
假設第二個程式被加入的網路的HostB中,那么由HostA傳來的信息如何能被正確的傳給程式B而不是傳給新加入的程式呢?這是因為每一個基於TCP/IP網路通訊的程式都被賦予了唯一的連線埠和連線埠號,連線埠是一個信息緩衝區,用於保留Socket中的輸入/輸出信息,連線埠號是一個16位無符號整數,範圍是0-65535,以區別主機上的每一個程式(連線埠號就像房屋中的房間號),低於256的連線埠號保留給標準應用程式,比如pop3的連線埠號就是110,每一個套接字都組合進了IP位址、連線埠、連線埠號,這樣形成的整體就可以區別每一個套接字。

相關分析

HostA上的程式A將一段信息寫入Socket中,Socket的內容被HostA的網路管理軟體訪問,並將這段信息通過HostA的網路接口卡傳送到HostB,HostB的網路接口卡接收到這段信息後,傳送給HostB的網路管理軟體,網路管理軟體將這段信息保存在HostB的Socket中,然後程式B才能在Socket中閱讀這段信息。
假設在圖1的網路中添加第三個主機HostC,那么HostA怎么知道信息被正確傳送到HostB而不是被傳送到HostC中了呢?基於TCP/IP網路中的每一個主機均被賦予了一個唯一的IP位址,IP位址是一個32位的無符號整數,由於沒有轉變成二進制,因此通常以小數點分隔,如:198.163.227.6,正如所見IP位址均由四個部分組成,每個部分的範圍都是0-255,以表示8位地址。
值得注意的是IP位址都是32位地址,這是IP協定版本4(簡稱Ipv4)規定的,目前由於IPv4地址已近耗盡,所以IPv6地址正逐漸代替Ipv4地址,Ipv6地址則是128位無符號整數。
假設第二個程式被加入圖1的網路的HostB中,那么由HostA傳來的信息如何能被正確的傳給程式B而不是傳給新加入的程式呢?這是因為每一個基於TCP/IP網路通訊的程式都被賦予了唯一的連線埠和連線埠號,連線埠是一個信息緩衝區,用於保留Socket中的輸入/輸出信息,連線埠號是一個16位無符號整數,範圍是0-65535,以區別主機上的每一個程式(連線埠號就像房屋中的房間號),低於256的短口號保留給標準應用程式,比如pop3的連線埠號就是110,每一個套接字都組合進了IP位址、連線埠、連線埠號,這樣形成的整體就可以區別每一個套接字。

流式套接字

套接字套接字
它是兩種可用的WindowsSockets類型中的一種。(另一種類型是數據文報套接字。)流式套接字提供沒有記錄邊界的數據流:可以是雙向的位元組流(應用程式是全雙工:可以通過套接字同時傳輸和接收)。可依賴流傳遞有序的、不重複的數據。(“有序”指數據包按傳送順序送達。“不重複”指一個特定的數據包只能獲取一次。)這能確保收到流訊息,而流非常適合處理大量數據。
網路傳輸層可將數據拆分為分組或若干個大小適當的數據包。CSocket類將為您處理打包和解包。
流基於顯式連線:套接字A請求與套接字B建立連線;套接字B接受或拒絕此連線請求。
打電話的情況與流非常相似:正常情況下,接聽方聽到您的話和您講話時的順序一樣,沒有重複和遺漏。流套接字適合檔案傳輸協定(FTP)這類實現,此協定有利於傳輸任意大小的ASCII或二進制檔案。
如果必須保證數據送達而且數據大小很大時,流式套接字優於數據文報套接字。有關流式套接字的更多信息,請參見WindowsSockets規範。該規範可在PlatformSDK中獲得。
MFC示例CHATTER和CHATSRVR都使用流式套接字。這些示例可能已經設計為使用數據文報套接字向網路上的所有接收套接字廣播。而目前的設計更好,這是因為:
廣播模型受制於網路“洪水”(或“風暴”)問題。
後來採用的客戶端-伺服器模型更有效。
流式模型提供可靠的數據傳輸,數據文報模型則未提供。
最終模型利用在CArchive類借給CSocket類的Unicode和ANSI套接字應用程式之間通信的能力。

注意事項

如果使用CSocket類,則必須使用流。如果將套接字類型指定為SOCK_DGRAM,則MFC斷言失敗
WindowsSockets示例列表
下列MFC示例程式闡釋了WindowsSockets功能:
CHATTER
CHATTER是一個Windows套接字客戶端示例應用程式。它是一個具有拆分視窗的單文檔界面(SDI)應用程式,允許用戶將訊息傳送到討論伺服器(CHATSRVR),討論伺服器然後將訊息同時傳送給其他多個CHATTER用戶。
通過使CHATTER應用程式向伺服器傳送廣播數據文報包而不是訊息流,可以在不使用客戶端/伺服器模型的情況下編寫CHATTER和CHATSRVR。然而,與流式套接字不同,數據文報套接字不能保證一定會被傳送;因此,一些訊息可能不會到達討論中的所有其他用戶。

運行示例

生成並運行CHATTER示例
打開解決方案chatter.sln。
在“生成”選單上單擊“生成”。
在“調試”選單上單擊“開始執行(不調試)”。
運行CHATTER時,有一個“Setup”對話框請求輸入以下內容:
Handle
用來定址所有訊息的名稱。例如,可以選擇“”。傳送的所有訊息的前面都會自動加上名稱“”。
Server
運行CHATSVR示例的計算機的IP位址。
Channel
標識要加入的討論的數字(一台計算機可以運行多個討論伺服器)。
提供了所有這些信息並單擊“OK”後,主應用程式視窗隨即出現。若要傳送訊息,請在下部窗格中鍵入訊息。按ENTER鍵傳送訊息。若要傳送多行訊息,請按CTRL+ENTER鍵。關鍵字

示例

此示例說明了以下關鍵字:
AfxGetApp、AfxMessageBox、CArchive::Flush、CArchive::IsStoring、CControlBar::EnableDocking、CControlBar::GetBarStyle、CControlBar::SetBarStyle、CDialog::DoModal、CDocument::DeleteContents、CDocument::GetFirstViewPosition、CDocument::GetNextView、CDocument::OnNewDocument、CEditView::GetEditCtrl、CEditView::SerializeRaw、CFrameWnd::DockControlBar、CFrameWnd::EnableDocking、CFrameWnd::OnCreateClient、CFrameWnd::SetActiveView、CObject::AssertValid、CObject::Dump、CObject::IsKindOf、CObject::Serialize、CRect::Size、CSplitterWnd::CreateView、CSplitterWnd::GetPane、CStatusBar::Create、CStatusBar::SetIndicators、CString::GetBuffer、CString::GetLength、CString::IsEmpty、CString::LoadString、CString::ReleaseBuffer、CToolBar::Create、CToolBar::LoadBitmap、CToolBar::SetButtons、CView::GetDocument、CView::OnDraw、CWinApp::AddDocTemplate、CWinApp::InitInstance、CWinApp::LoadStdProfileSettings、CWinApp::OnFileNew、CWnd::DestroyWindow、CWnd::DoDataExchange、CWnd::GetClientRect、CWnd::GetWindowText、CWnd::GetWindowTextLength、CWnd::KillTimer、CWnd::OnChar、CWnd::OnCreate、CWnd::OnTimer、CWnd::PreCreateWindow、CWnd::SetTimer、CWnd::SetWindowText、SetWindowText、rand、wsprintf
注意一些示例(如此示例)尚未經過修改以反映VisualC++嚮導、庫和編譯器的變化,但仍說明了如何完成所需的任務。
參見MFC示例
CHATSRVR
CHATSRVR是Windows套接字伺服器示例應用程式,它是一個單文檔界面(SDI)應用程式,用於為CHATTER示例的客戶端實現討論伺服器。
通過使CHATTER應用程式向伺服器傳送廣播數據文報包而不是訊息流,可以在不使用客戶端/伺服器模型的情況下編寫CHATTER和CHATSRVR。然而,與流式套接字不同,數據文報套接字不能保證一定會被傳送;因此,一些訊息可能不會到達討論中的所有其他用戶。生成並運行示例
生成並運行CHATSRVR示例
打開解決方案chatsrvr.sln。
在“生成”選單上單擊“生成”。
在“調試”選單上單擊“開始執行(不調試)”。
運行CHATSRVR時會顯示一個請求輸入“Channel”的“Discussion”對話框。“Channel”是標識要支持的討論的數字(一台計算機可以運行多個討論伺服器)。提供了此信息並單擊“OK”後,主應用程式視窗隨即出現。關鍵字

通信

要通過Internet進行通信,至少需要一對套接字,其中一個運行在客戶端,稱之為ClientSocket,另一個運行於伺服器端面,稱為ServerSocket。根據連線啟動的方式以及本地要連線的目標,套接字之間的連線過程可以分為三個步驟:伺服器監聽、客戶端請求、連線確認。
伺服器監聽是指服務端套接字並不定位具體的客戶端套接字,而是處於等待連線的狀態,實時監控網路狀態。
客戶端請求是由客戶端的套接字提出連線請求,要連線的目標是伺服器端套接字。為此,客戶端的套接字必須首先描述它要連線的伺服器的套接字,指出伺服器套接字的地址和連線埠號,然後再向伺服器端套接字提出連線請求。
連線確認是當伺服器端套接字監聽到或者說接收到客戶端套接字的連線請求時,它就回響客戶端套接字的請求,建立一個新的執行緒,把伺服器端套接字的信息傳送給客戶端,一旦客戶端確認了此連線,連線即可建立。而伺服器端繼續處於監聽狀態,繼續接收其他客戶端的連線請求。
使用套接字進行數據處理有兩種基本模式:同步和異步。
同步模式:
同步模式的特點是在通過Socket進行連線、接收、傳送數據時,客戶機和伺服器在接收到對方回響前會處於阻塞狀態,即一直等到收到對方請求進才繼續執行下面的語句。可見,同步模式只適用於數據處理不太多的場合。當程式執行的任務很多時,長時間的等待可能會讓用戶無法忍受。
異步模式:
異步模式的特點是在通過Socket進行連線、接收、傳送操作時,客戶機或伺服器不會處於阻塞方式,而是利用callback機制進行連線、接收、傳送處理,這樣就可以在調用傳送或接收的方法後直接返回,並繼續執行下面的程式。可見,異步套接字特別適用於進行大量數據處理的場合。
使用同步套接字進行編程比較簡單,而異步套接字編程則比較複雜。

相關詞條

相關搜尋

熱門詞條

聯絡我們