Socket通信

      socket的英文原義是“孔”或“插座”。作爲4BDS UNIX的進程通信機制,取後一種意思。通常也稱作"套接字",用於描述IP地址和端口,是一個通信鏈的句柄。在Internet上的主機一般運行了多個服務軟件,同時提供幾種服務。每種服務都打開一個Socket,並綁定到一個端口上,不同的端口對應於不同的服務。Socket正如其英文原意那樣,象一個多孔插座。一臺主機猶如佈滿各種插座的房間,每個插座有一個編號,有的插座提供220伏交流電, 有的提供110伏交流電,有的則提供有線電視節目。 客戶軟件將插頭插到不同編號的插座,就可以得到不同的服務。

      socket非常類似於電話插座。以一個國家級電話網爲例,電話的通話雙方相當於相互通信的2個進程,區號是它的網絡地址;區內一個單位的交換機相當於一臺主機,主機分配給每個用戶的局內號碼相當於socket號。任何用戶在通話之前,首先要佔有一部電話機,相當於申請一個socket;同時要知道對方的號碼,相當於對方有一個固定的socket。然後向對方撥號呼叫,相當於發出連接請求(假如對方不在同一區內,還要撥對方區號,相當於給出網絡地址)。假如對方在場並空閒(相當於通信的另一主機開機且可以接受連接請求),拿起電話話筒,雙方就可以正式通話,相當於連接成功。雙方通話的過程,是一方向電話機發出信號和對方從電話機接收信號的過程,相當於向socket發送數據和從socket接收數據。通話結束後,一方掛起電話機相當於關閉socket,撤消連接。

在電話系統中,一般用戶只能感受到本地電話機和對方電話號碼的存在,建立通話的過程,話音傳輸的過程以及整個電話系統的技術細節對他都是不透明的,這也與socket機制非常相似。socket利用網間網通信設施實現進程通信,但它對通信設施的細節毫不關心,只要通信設施能提供足夠的通信能力,它就滿足了。至此,我們對socket進行了直觀的描述。抽象出來,socket實質上提供了進程通信的端點。進程通信之前,雙方首先必須各自創建一個端點,否則是沒有辦法建立聯繫並相互通信的。正如打電話之前,雙方必須各自擁有一臺電話機一樣。在網間網內部,每一個socket用一個半相關描述:
(協議,本地地址,本地端口)
一個完整的socket有一個本地唯一的socket號,由操作系統分配。
最重要的是,socket 是面向客戶/服務器模型而設計的,針對客戶和服務器程序提供不同的socket系統調用。客戶隨機申請一個socket (相當於一個想打電話的人可以在任何一臺入網電話上撥號呼叫),系統爲之分配一個socket號;服務器擁有全局公認的 socket ,任何客戶都可以向它發出連接請求和信息請求(相當於一個被呼叫的電話擁有一個呼叫方知道的電話號碼)。

socket利用客戶/服務器模式巧妙地解決了進程之間建立通信連接的問題。服務器socket 半相關爲全局所公認非常重要。讀者不妨考慮一下,兩個完全隨機的用戶進程之間如何建立通信?假如通信雙方沒有任何一方的socket 固定,就好比打電話的雙方彼此不知道對方的電話號碼,要通話是不可能的。

什麼是socket

所謂socket通常也稱作"套接字",應用程序通常通過"套接字"向網絡發出請求或者應答網絡請求。以J2SDK-1.3爲例,Socket和ServerSocket類庫位於java .net包中。ServerSocket用於服務器端,Socket是建立網絡連接時使用的。在連接成功時,應用程序兩端都會產生一個Socket實例,操作這個實例,完成所需的會話。對於一個網絡連接來說,套接字是平等的,並沒有差別,不因爲在服務器端或在客戶端而產生不同級別。不管是Socket還是ServerSocket它們的工作都是通過SocketImpl類及其子類完成的。

重要的Socket API

重要的SocketAPI:java .net.Socket繼承於java.lang.Object,有八個構造器,其方法並不多,下面介紹使用最頻繁的三個方法,其它方法大家可以見JDK-1.3文檔。
Accept方法用於產生"阻塞",直到接受到一個連接,並且返回一個客戶端的Socket對象實例。"阻塞"是一個術語,它使程序運行暫時"停留"在這個地方,直到一個會話產生,然後程序繼續;通常"阻塞"是由循環產生的。
getInputStream方法獲得網絡連接輸入,同時返回一個InputStream對象實例。

getOutputStream方法連接的另一端將得到輸入,同時返回一個OutputStream對象實例。注意:其中getInputStream和getOutputStream方法均可能會產生一個IOException,它必須被捕獲,因爲它們返回的流對象,通常都會被另一個流對象使用。

SOCKET連接過程

根據連接啓動的方式以及本地套接字要連接的目標,套接字之間的連接過程可以分爲三個步驟:服務器監聽,客戶端請求,連接確認。
服務器監聽:是服務器套接字並不定位具體的客戶端套接字,而是處於等待連接的狀態,實時監控網絡狀態。
客戶端請求:是指由客戶端套接字提出連接請求,要連接的目標是服務器端的套接字。爲此,客戶端套接字必須首先描述它要連接的服務器的套接字,指出服務器端套接字的地址端口號,然後就向服務器端套接字提出連接請求。
連接確認:是指當服務器套接字監聽到或者說接收到客戶端套接字的連接請求,它就響應客戶端套接字的請求,建立一個新的線程,把服務器端套接字的描述發給客戶端,一旦客戶端確認了此描述,連接就建立好了。而服務器套接字繼續處於監聽狀態,繼續接收其他客戶端套接字的連接請求。

如何開發一個Server-Client模型的程序

開發原理:
服務器,使用ServerSocket監聽指定的端口,端口可以隨意指定(由於1024以下的端口通常屬於保留端口,在一些操作系統中不可以隨意使用,所以建議使用大於1024的端口),等待客戶連接請求,客戶連接後,會話產生;在完成會話後,關閉連接。
客戶端,使用Socket對網絡上某一個服務器的某一個端口發出連接請求,一旦連接成功,打開會話;會話完成後,關閉Socket。客戶端不需要指定打開的端口,通常臨時的、動態的分配一個1024以上的端口。
Socket接口是TCP/IP網絡的API,Socket接口定義了許多函數或例程,程序員可以用它們來開發TCP/IP網絡上的應用程序。要學Internet上的TCP/IP網絡編程,必須理解Socket接口。Socket接口設計者最先是將接口放在Unix操作系統裏面的。如果瞭解Unix系統的輸入和輸出的話,就很容易瞭解Socket了。網絡的Socket數據傳輸是一種特殊的I/O,Socket也是一種文件描述符。Socket也具有一個類似於打開文件的函數調用Socket(),該函數返回一個整型的Socket描述符,隨後的連接建立、數據傳輸等操作都是通過該Socket實現的。

常用的Socket類型

有兩種:流式Socket(SOCK_STREAM)和數據報式Socket(SOCK_DGRAM)。流式是一種面向連接的Socket,針對於面向連接的TCP服務應用;數據報式Socket是一種無連接的Socket,對應於無連接的UDP服務應用。Socket爲了建立Socket,程序可以調用Socket函數,該函數返回一個類似於文件描述符的句柄。socket函數原型爲:int socket(int domain,int type,intprotocol);domain指明所使用的協議族,通常爲PF_INET,(其與addrinfo 裏的 AF_INET在現在看來是相同的。只是歷史上人們曾構想將AF(地址家族address family)與PF(protocol family 協議家族)分開,但實際上這種區分並未真正推廣,所以現在AF_INET和PF_INET具有相同的意義。其中AF_INET是基於IPv4而PF_INET基於IPv6)表示互聯網協議族(TCP/IP協議族);type參數指定socket的類型:SOCK_STREAM 或SOCK_DGRAM,Socket接口還定義了原始Socket(SOCK_RAW),允許程序使用低層協議;protocol通常賦值0。Socket()調用返回一個整型socket描述符,你可以在後面的調用使用它。Socket描述符是一個指向內部數據結構指針,它指向描述符表入口。調用Socket函數時,socket執行體將建立一個Socket,實際上"建立一個Socket"意味着爲一個Socket數據結構分配存儲空間。Socket執行體爲你管理描述符表。兩個網絡程序之間的一個網絡連接包括五種信息:通信協議、本地協議地址本地主機端口、遠端主機地址和遠端協議端口。Socket數據結構中包含這五種信息。socket在測量軟件中的使用也很廣泛。
現在越來越多企業採用這種,當然也有人曾經想將地址協議分開,但實際的意義上並未實行到,現在還在使用原始的類型,它是指向低層協議的一種。

socket函數

簡介

應用程序調用socket函數來創建一個能夠進行網絡通信套接字
1
2
3
4
5
/* 頭文件 */
#include <sys/types.h>
#include <sys/socket.h>
/* 函數原型 */
intsocket(intdomain, inttype, intprotocol);
第一個參數指定應用程序使用的通信協議的協議族,對於TCP/IP協議族,該參數置AF_INET;
第二個參數指定要創建的套接字類型,流套接字類型爲SOCK_STREAM、數據報套接字類型爲SOCK_DGRAM、原始套接字SOCK_RAW(WinSock接口並不適用某種特定的協議去封裝它,而是由程序自行處理數據包以及協議首部);
第三個參數指定應用程序所使用的通信協議。此參數可以指定單個協議系列中的不同傳輸協議。在Internet通訊域中,此參數一般取值爲0,系統會根據套接字的類型決定應使用的傳輸層協議。
該函數如果調用成功就返回新創建的套接字的描述符,如果失敗就返回INVALID_SOCKET。(Linux下失敗返回-1)套接字描述符是一個整數類型的值。每個進程的進程空間裏都有一個套接字描述符表,該表中存放着套接字描述符和套接字數據結構的對應關係。該表中有一個字段存放新創建的套接字的描述符,另一個字段存放套接字數據結構地址,因此根據套接字描述符就可以找到其對應的套接字數據結構。每個進程在自己的進程空間裏都有一個套接字描述符表但是套接字數據結構都是在操作系統內核緩衝裏。

創建流套接字的例子

1
2
3
structprotoent *ppe;
ppe=getprotobyname("tcp");
SOCKET ListenSocket=socket(PF_INET,SOCK_STREAM,ppe->p_proto);


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章