浅谈Socket编程
淺談Socket編程
說到Socket,想必大家會覺得陌生又熟悉。許多同學聽說過Socket,但僅僅知道它翻譯成中文叫做套接字,除此之外似乎并沒有太多的了解了。那么今天我就來拋磚引玉地聊一聊Socket。有人說
The lower application layers are all about socket programming
應用的底層全是和socket打交道
一看到涉及底層,有的同學就表示:
其實這些東西并不深奧,只要花一些時間去看,肯定是能夠看懂的,并且一但找到了點兒感覺,會覺得Socket非常有趣。
你難道不好奇瀏覽器是怎樣和web服務器勾搭在一起來取悅你的嗎?許多網絡應用都通過Socket來交流,所以Socket在網絡編程里占有了很重要的地位。
那么言歸正傳,到底什么是Socket的呢?——大學教材上的答案是套接字。我個人覺得這是一個不太好的翻譯,雖然說仔細一想有那么點兒意思,但是99%的人即使看見套接字這個詞,依然不知道是什么鬼,所以沒有翻譯的必要。就像Rap你硬要說中文翻譯叫拉普也沒啥意義對吧。
在Unix中,有一種說法叫
Everything is a file
一切皆文件
所以你只需要記住Socket是某種類型文件的抽象
怎么理解這句話呢?想象一下,假設你要開發一個網絡應用,需要在兩個客戶端之間發消息。整個過程可能包含以下步驟:
- 客戶端組裝數據
- 客戶端之間約定好數據格式
- 客戶端向指定地址發送請求
- DNS服務器解析請求地址
- DNS沒有找到地址,然后跳轉到另一個DNS,一直到找到為止
- 返回客戶端真實的IP
- 客戶端向對應IP建立連接請求(三次握手)
- 開始發送數據,窗口以2的k次冪大小滑動
……
以上省略一本頁數為1047的《TCP/IP》
有人可能已經噴了,你不是說Socket編程很簡單嗎,這還叫簡單?
正因為這很復雜,所以前人們對這個過程進行了一種抽象,來幫助我們編程。
你不就是想把數據發給對方嗎?組裝數據然后發給某人這個過程,和組裝好數據然后寫到某個文件里有什么區別呢?對了,沒有區別。
Socket就是一種特殊的文件。它是一個連接了兩個用戶的文件,任何一個用戶向Socket里寫數據,另一個用戶都能看得到,不管這兩個用戶分布在世界上相距多么遙遠的角落,感覺就像坐在一起傳紙條一樣。
這么講Socket應該更容易理解吧?這種抽象是非常重要的,因為它屏蔽了更底層的東西,我就想寫個程序發送下數據,為什么要關系物理層怎么傳輸呢,對吧。
所以有了Socket的概念之后,我們在兩個客戶端之間發送消息可能就是這樣的: - 指定對方的地址
- 打開一個和對方連接的Socket
- 把Socket當成普通的文件,往里寫數據
- 要是發現Socket里有數據,就讀出來,那必然是對方發過來的
這樣的話,網絡編程是不是就非常簡單了呢?
那么下面我們用Go語言作為示例,演示一下。
端口是什么概念?可以近似這么想:一臺電腦就是你家的小區,你買東西如果填的地址是你家小區,那么快遞員最多能把東西送到小區門口;但是如果你寫上了你家的門牌號,那么快遞員就能送到你家門口。同樣的,電腦上同時運行著很多程序,比如QQ,旺旺…但是電腦只有只有一個IP地址,一條消息來了沒人知道這個消息是給誰的,于是就有了端口的概念。QQ在這臺電腦的4567端口,旺旺在這臺電腦1234端口。發消息的人只要知道它在什么端口,就能準確地把消息發過來了。
同樣的,網絡通信兩端的人得事先約定好一個端口,然后一個人守著這個端口,待另一方連接了這個端口,這才算建立了Socket連接。就好兩個人打電話,不需要關心信號怎么轉換和傳輸,但在建立這次通話之前必須有人撥號,同時有人守在電話旁。
于是上面的代碼應該就可以理解了吧?
一個程序猿走到"localhost:6666"這個“電話”旁邊
然后坐下來等電話響
fd,err := net.ListenTcp("tcp", tcpAddr)他也不知道女朋友什么時候打電話過來,于是開始了漫長的等待
//一個死循環 for { conn,err := fd.Accept() //電話沒有響就一直堵在上面這條語句 }在漫長地等待中,突然電話響了,然后開始了一段佳話(程序終于不堵了,接著向下執行)
go Handle(conn)Handle方法就用來處理對話,數據都在conn里面,只需要學習相關的API就能知道怎么把具體的內容取出來了。
整個過程是不是很簡單?
有些機智的同學可能已經發現了,要這樣的話,兩個人都在等對方打電話過來,豈不是就終身無緣了(這種誤會就像韓劇)。對的,所以我們還需要知道,如何給對方撥號。這是很關鍵的一步,一般妹子不好意思,那么自然我們得上了。
怎么撥號呢?請看代碼:
解釋一下,一般妹子都比較含蓄,告訴你聯系方式不那么直接,你得破解一下
tcpAddr := net.ResolveTcpAddr("tcp", "localhost:6666")呵呵,嘴上說不要身體卻很誠實嘛,這么容易就破解了。(其實是Go的包比較好用好嗎!)
然后按著電話號撥打電話
電話打通了,conn就代表這次通話。屌絲們已經急不可耐了,于是大喊一句:
_, err = conn.Write([]byte("妹子,約嗎?"))為什么我第一個返回值用_,這表示我不想知道函數的返回結果,即Write了多少個字節。我問妹子約不約,你說我關不關心這句話包含幾個字節?
result, err := ioutil.ReadAll(conn)妹子給的回復就在result里,慢慢去琢磨吧……
以上示例并不完整,完整的示例網上到處可見,希望大家能自己寫一寫。
本篇只是粗淺地講了講什么是Socket編程以及基本過程,之后會有更細致地講解(比如:并發)。
作者: PHPBird?
鏈接:http://www.imooc.com/article/1668
來源:慕課網
轉載于:https://www.cnblogs.com/wangjian8888/p/6828117.html
總結
以上是生活随笔為你收集整理的浅谈Socket编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JNI中java类型的简写
- 下一篇: windows 程序员电脑设置