與socket的第一次「約會」
注: 這是乙個針對 網路開發領域初學者 的系列文章,可作為《.net 4.0 物件導向程式設計漫談 》一書的擴充閱讀,寫作過程中我假設讀者可以對照閱讀此書的相關章節,不再浪費筆墨重複介紹相關的內容。
對於其他型別的讀者,除非您已經有相應的.net 技術背景與一定的開發經驗,否則,閱讀中可能會遇到困難。
我希望這系列文章能讓讀者領略到網路開發的魅力!
本文如有錯誤,敬請回貼指正。
謝謝大家!
金旭亮
《 開篇語—— 無網不勝》
《 ip知多少》
《我在「網」 ** 》
在前面的文章中,我們已經介紹了使用.net平台開發網路應用程式諸如ip位址、網路介面之類的背景知識,本文將介紹.net網路應用程式的主角--socket。如果把socket比喻為一位「美女」,那麼有關她的「愛情故事」實在太多,而本系列後繼的文章,就圍繞著這位「美女」所展開。
1 socket美女的「家庭背景」
socket,中文譯為「套接字」,最早在unix中引入並得到廣泛應用,後來微軟在設計windows時引入了unix中的這個概念和相應的設計理念,並針對windows的特性略作調整,形成了windows平台上的socket,簡稱為「winsock」,並為開發者提供了一整套的api,稱為「windows winsock win32 api 」。
winsock經歷了兩個版本,windows sockets 2是目前用得最多的版本(參看 http://en.wikipedia.org/wiki/winsock ),微軟似乎從來沒有宣布要開發winsock 3,也許「永遠也不會有」了。
圖 1所示為.net平台下網路應用程式的層次架構:
圖 1winsock在底層使用乙個執行於作業系統核心的系統驅動(windows sockets knernel-mode driver)tcpip.sys,由它們負責管理網路連線和緩衝管理。
還有另乙個驅動afd.sys(ancillary function driver for winsock)則用於支援基於 window socket的應用程式,比如ftp、telnet等,被稱為「 windows nt 套接字驅動程式 」。
早期的windows開發者,需要使用c/c++去呼叫winsock,比如mfc就提供了乙個「csocket」類封裝底層的socket。
.net也提供了一組類來封裝winsock win32 api,這些類集中於system.net這一命名空間中,其中的核心型別就是socket。
socket類是對winsock api乙個很淺的封裝,擁有不少方法直接對應於winsock中的c/c++函式,比如poll、select、iocontrol等。
socket有乙個handle屬性,它引用位於作業系統核心的socket核心物件。
了解了socket這位「美女」的「家庭背景」之後,在與她進行第一次「約會」之前,我們不妨弄清楚乙個問題:
現在我們還有必要掌握sokcet程式設計技術嗎?
2 socket是否已人老珠黃?
基於socket開發網路應用程式已經有很多年的歷史了,現在的新技術層出不窮,在.net平台之上,wcf大有「一統江湖」的勢頭,socket是否真的「人老珠黃」?
請看圖 2所示的多層「松花蛋」:
圖 2
3 第乙個socket應用程式
一般我們都將網路應用中用於提供「服務」的一方稱為「服務端應用程式(server)」,另一方訪問這些服務的稱為「客戶端應用程式(client)」。server端和client端的socket用法是不一樣的。
3.1 服務端應用程式
開發網路程式的第一步,是建立socket物件,以下是示例**:
socket newsock = new socket(
addressfamily.internetwork, //使用ipv4
sockettype.stream, //使用可靠的雙向資料流,不儲存資訊邊界
protocoltype.tcp //使用tcp協議
);緊接著,需要將socket物件「繫結(bind) 」到乙個「終結點(ipendpoint的例項)」。
ipendpoint ipep = new ipendpoint(ip位址,開啟埠); //繫結
newsock.bind(ipep);
注意:
wcf中也有「繫結」,但wcf中的「繫結」的含義要豐富得多,它其實是一組特殊的物件,它的主要功能是建立用於實現wcf應用程式間相互通訊的「通道棧」,wcf基類庫中提供了一堆的「繫結」,特定的繫結使用特定的通訊協議和技術,比如nettcpbinding採用tcp協議,netmsmqbinding則使用了微軟訊息佇列。
socket物件繫結網路介面之後,就可以監聽並等待客戶端連線了:
newsock.listen(10); //開始監聽
socket client = newsock.accept(); //等待客戶端連線
注意:
負責監聽的socket不負責傳送與接收資料,而accept方法返回的socket可以用於接收和傳送資料,但不能用於接收新的連線,同時,其remoteendpoint方法可以獲取遠端客戶端的ip位址和使用的埠
以下**呼叫剛得到的socket物件的receive方法接收客戶端發來的資料:
byte data = new byte[1024];
int r ecv = client.receive(data);
socket.receive方法也是乙個「阻塞」的同步方法,它將收到的資料儲存到乙個位元組陣列中,這個位元組陣列通常稱為「資料緩衝區」。
receive方法的返回值代表接收的資料位元組數。以下**使用這一返回值了解客戶端到底發來了什麼訊息:
console.writeline(encoding.utf8 .getstring(data, 0, recv ));
資料接收完畢,服務端就可以斷開客戶的連線:
client.shutdown(socketshutdown.both); //通知os,不再接收與傳送資料
client.close(); //關閉socket
完成資料傳送任務之後,注意應該及時地關閉socket。這通常分為兩步:
(1)呼叫shutdown方法通知tcp/ip協議棧傳送所有未傳送的資料,或停止接收資料
(2)呼叫close方法關閉套接字。
socket本身對應著乙個核心物件,它有乙個控制代碼(handle)供作業系統核心進行管理。因此,它不再有用時必須及時地被關閉,否則,有可能會造成嚴重的問題。
socket本身實現了idisposable介面,所以也可以使用using關鍵字實現「自動釋放」:
using (newsock)
//自動關閉newsock
3.2 客戶端應用程式
客戶端應用程式與服務端大同小異:
首先建立好乙個socket物件,然後再呼叫其connect方法建立到服務端的連線,如果之前socket沒有使用bind方法指定乙個埠,connect方法會自動選擇乙個未用的埠:
socket server = new socket( addressfamily.internetwork,
sockettype.stream, protocoltype.tcp );
server.connect(服務端的ip終結點);
如果connect方法沒有丟擲異常,則表示成功連線伺服器,現在,就可以使用socket物件的send方法傳送資料,資料同樣儲存於乙個資料緩衝區(其實就是乙個byte)中:
server.send(encoding.utf8 .getbytes(要傳送的訊息));
注意這裡選擇的字串編碼方式必須要與服務端一致,否則,將導致服務端無法正確地解碼出字串。
資料傳送完畢,關閉套接字就行了。
3.3 處理網路應用程式中的異常
socket物件的connect、send、receive等方法都有可能出錯,這時,.net基類庫將丟擲乙個socketexception,它實際上封裝的是底層winsock出錯資訊。
每乙個socketexception物件都有乙個對應的錯誤號,其含義是由底層的winsock定的。比如錯誤號為10048的socketexception其含義是:位址已被使用。發生這一異常的原因通常是你嘗試把兩個socket物件繫結到同乙個ipendpoint。
以下是socket網路應用程式中的典型**框架:
socket remote=new socket(……);
trycatch (socketexception e)
,原因:,
nativeerrorcode:,socketerrorcode:", iep.address,
e.message, e.nativeerrorcode, e.socketerrorcode);
}finally
示例專案introducesocket展示了本文所介紹的知識(圖 3)。
圖 3到此,我們與「socket美女」的「第一次約會」到此結束。您對她的第一印象如何?
約會細節第一次
1 手機靜音 2 第一次的約會禮物 3 注意要把指甲剪乾淨 4.幽默 5 口香糖,安全套,手機充滿電,詳細的約會計畫,看好天氣預報,洗好澡,刷好牙,做好髮型,研究好交通。最後,一顆淡定的心,以及提前準備出來的至少10條話題!7 有主見 8 如何浪漫接吻。9 10 可以一起共進晚餐或者在公園散步,晚上...
正常的約會是 第一次約會不像約會而是臨時起約
這心態其實是司馬昭之心。你知道 我知道,女方當然也知道。既然你所有邀約的背後,都需要她日後償付某種代價。那在有這前提的認知下,女人當然會對邀約顯得謹慎的多。所以如果她覺得對你的認識還不足,對於你這個人的性格條件尚有疑慮,還不確定你這人是否能讓她安心下,她為何要 授人以柄 吃飯也好 看電影也好 甚至演...
第一次使用套接字socket程式設計
伺服器端 server new serversocket 18811 18811為埠號這樣就可以建立好乙個socket服務端 socket socket server.accept accept 阻塞型獲取客戶端連線方式 in new inputstreamreader socket.getinpu...