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