socket編程的幾個(gè)問(wèn)題

網(wǎng)絡(luò)編程離不開(kāi)socket上荡,接觸不多時(shí)總覺(jué)得簡(jiǎn)單,無(wú)非是bind()馒闷;listen()酪捡;accept();send()纳账;recv()幾個(gè)函數(shù)癡癡用上逛薇,能跑就不管三七二十一了。最近需要寫(xiě)個(gè)http代理疏虫,遇上幾個(gè)問(wèn)題永罚。

socket的本質(zhì)

從前認(rèn)死理啤呼,怎么就recv()收到網(wǎng)絡(luò)報(bào)文,功能還這么強(qiáng)大呢袱,嗅探官扣,代理,服務(wù)器都用上它羞福,就差沒(méi)往硬件上想惕蹄,現(xiàn)在想來(lái)也算是和自己和解了,在我的理解治专,socket是從傳輸層提取出的一套程序接口卖陵,供應(yīng)用層使用,使我們不必面對(duì)實(shí)際的tcp/ip復(fù)雜的傳輸過(guò)程张峰。它是一套規(guī)則和機(jī)制泪蔫,靈感來(lái)源于Unix一切皆文件的設(shè)計(jì),socket就像一個(gè)文件夾挟炬,創(chuàng)建鸥滨,讀取,寫(xiě)出谤祖,關(guān)閉婿滓,只不過(guò)這里對(duì)應(yīng)的是網(wǎng)絡(luò)數(shù)據(jù)。

socket中的accept()

accept()函數(shù)返回值是客戶端socket和客戶端地址信息粥喜,它創(chuàng)建了一個(gè)新的socket凸主,稱它為cli_socket,而原先綁定的socket稱為soc额湘。這里使我疑惑的地方就在于為什么同一個(gè)端口下有兩個(gè)socket的存在卿吐。不是一個(gè)端口標(biāo)識(shí)唯一的socket嗎?
事實(shí)上锋华,不是一個(gè)端口唯一標(biāo)識(shí)嗡官,而是五元組標(biāo)識(shí)一個(gè)socket,(source ip, source port, destination ip, destination port, protocol)毯焕,而本地綁定的socket并不算一個(gè)完整的socket衍腥,它只包含三元組,即(destination ip, destination port, protocol)纳猫,而accept()函數(shù)接受了來(lái)自客戶端的信息婆咸,至此完成一個(gè)完整的socket鏈接,這個(gè)cli_socket用于接收和發(fā)送數(shù)據(jù)芜辕,而soc則繼續(xù)用于監(jiān)聽(tīng)客戶端的connect請(qǐng)求尚骄。
再說(shuō)明一點(diǎn),雖說(shuō)五元組唯一標(biāo)識(shí)一個(gè)socket侵续,并不是說(shuō)這個(gè)端口就只能給一個(gè)socket使用倔丈,若是五元組中有不同的元素憨闰,比如說(shuō)客戶端ip和端口不同,那就是另一個(gè)socket需五,它和服務(wù)器端相同的端口和ip構(gòu)成了新的五元組起趾,比如說(shuō)服務(wù)器端的80端口供多個(gè)客戶端使用。
總的來(lái)說(shuō)這些都是前人留下的規(guī)定警儒,有的也不見(jiàn)得多明智,但目前還是主流眶根,所以還是有必要知道蜀铲。
參考1
參考2

socket中的數(shù)據(jù)接收問(wèn)題

因?yàn)閷?xiě)的是一個(gè)代理,所以既要當(dāng)客戶端也要當(dāng)服務(wù)端属百,在充當(dāng)客戶端過(guò)程中记劝,需要和web服務(wù)器通信,很簡(jiǎn)單的一個(gè)建立連接族扰,接收數(shù)據(jù)厌丑,是這樣的:

SerSock = socket(AF_INET, SOCK_STREAM)
SerSock.connect(SerAddr)
SerSock.send(CMessage)
message = SerSock.recv(4096)
SerSock.close()

就是創(chuàng)建,連接渔呵,發(fā)送怒竿,接收,關(guān)閉的過(guò)程扩氢,但是報(bào)錯(cuò)耕驰,broken pipe。說(shuō)是服務(wù)端還沒(méi)傳完數(shù)據(jù)录豺,客戶端就關(guān)閉了連接朦肘。
將接收到的數(shù)據(jù)輸出了一下,發(fā)現(xiàn)數(shù)據(jù)都沒(méi)傳完双饥,是這種:

Screenshot from 2017-07-12 22-10-34.png

細(xì)想媒抠,才知服務(wù)器傳送數(shù)據(jù)并不是一次性傳完的,學(xué)過(guò)計(jì)算機(jī)網(wǎng)絡(luò)的都知道咏花,傳輸層會(huì)將數(shù)據(jù)進(jìn)行分片傳輸趴生,選擇不同的路徑傳送過(guò)來(lái)再組織到一起。那么分片的大小是多大呢迟螺?每個(gè)以太網(wǎng)幀都有最小的大小64bytes最大不能超過(guò)1518bytes冲秽,參考

將代碼一改:

    SerSock = socket(AF_INET, SOCK_STREAM)
    SerSock.connect(SerAddr)
    SerSock.send(CMessage)
    FromSMessage = ''
    while True:
        message = SerSock.recv(4096)
        if not message:
            break
        FromSMessage += message
        SerSock.close()

可順利運(yùn)行矩父。

socket中的非阻塞問(wèn)題

代理程序雖然能運(yùn)行锉桑,但訪問(wèn)一多就會(huì)崩掉。這里需要知道的是窍株,socket中的send()民轴,recv()函數(shù)都是阻塞函數(shù)攻柠,也就是說(shuō)若數(shù)據(jù)沒(méi)有發(fā)送完畢或者沒(méi)有接收完畢,函數(shù)是不會(huì)返回的后裸,那么隨著accept的客戶端請(qǐng)求多了瑰钮,內(nèi)存占用溢出,就會(huì)崩掉微驶。怎樣設(shè)計(jì)一個(gè)非阻塞的socket程序呢浪谴?
這里主要講一下select這個(gè)對(duì)象,利用select對(duì)象的select()函數(shù)可以實(shí)現(xiàn)非阻塞因苹,簡(jiǎn)單看一下:

select.select(rlist, wlist, xlist[, timeout])

select()的參數(shù)為3個(gè)列表:第一列表為讀取輸入數(shù)據(jù)的對(duì)象苟耻;第2個(gè)接收要發(fā)送的數(shù)據(jù),第3個(gè)存放errors扶檐,加上一個(gè)超時(shí)設(shè)置凶杖。
返回值有三個(gè):readable,writable款筑,exceptional
readable有3種可能:對(duì)于用來(lái)偵聽(tīng)連接主服務(wù)器socket智蝠,表示已準(zhǔn)備好接受一個(gè)到來(lái)的連接;對(duì)于已經(jīng)建立并發(fā)送數(shù)據(jù)的鏈接奈梳,表示有數(shù)據(jù)到來(lái)杈湾;如果沒(méi)數(shù)據(jù)到來(lái),表示鏈接已經(jīng)關(guān)閉攘须。
writable的情況:連接隊(duì)列中有數(shù)據(jù)毛秘,發(fā)送下一條消息。如果隊(duì)列中無(wú)數(shù)據(jù)阻课,則從output隊(duì)列中刪除叫挟。
socket有錯(cuò)誤,也要從output隊(duì)列中刪除限煞。
所以這里實(shí)現(xiàn)非阻塞大體流程就是抹恳,select函數(shù)輪循,看有那個(gè)socket隊(duì)列有需要讀或?qū)懙臄?shù)據(jù)署驻,有就全部接收或發(fā)送奋献,沒(méi)有就忙別的。代碼大體如下:

def nonblocking(self):
        inputs=[self.client,self.target]
        while True:
            readable,writeable,errs=select.select(inputs,[],inputs,3)
            if errs:
                break
            for soc in readable:
                data=soc.recv(self.BUFSIZE)
                if data:
                    if soc is self.client:
                        self.target.send(data)
                    elif soc is self.target:
                        self.client.send(data)
                else:
                    break
        self.client.close()
        self.target.close()

參考1
參考2

至此旺上,socket問(wèn)題肯定不止于此瓶蚂,經(jīng)事尚少,暫且留意了這些宣吱,做個(gè)總結(jié)窃这,也希望能對(duì)他人有所幫助,不對(duì)之處還望指正征候。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末杭攻,一起剝皮案震驚了整個(gè)濱河市祟敛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌兆解,老刑警劉巖馆铁,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異锅睛,居然都是意外死亡埠巨,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)现拒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)乖订,“玉大人,你說(shuō)我怎么就攤上這事具练。” “怎么了甜无?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵扛点,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我岂丘,道長(zhǎng)陵究,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任奥帘,我火速辦了婚禮铜邮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘寨蹋。我一直安慰自己松蒜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布已旧。 她就那樣靜靜地躺著秸苗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪运褪。 梳的紋絲不亂的頭發(fā)上惊楼,一...
    開(kāi)封第一講書(shū)人閱讀 49,821評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音秸讹,去河邊找鬼檀咙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛璃诀,可吹牛的內(nèi)容都是我干的弧可。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼劣欢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼侣诺!你這毒婦竟也來(lái)了殖演?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤年鸳,失蹤者是張志新(化名)和其女友劉穎趴久,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體搔确,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡彼棍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了膳算。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片座硕。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖涕蜂,靈堂內(nèi)的尸體忽然破棺而出华匾,到底是詐尸還是另有隱情,我是刑警寧澤机隙,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布蜘拉,位于F島的核電站,受9級(jí)特大地震影響有鹿,放射性物質(zhì)發(fā)生泄漏旭旭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一葱跋、第九天 我趴在偏房一處隱蔽的房頂上張望持寄。 院中可真熱鬧,春花似錦娱俺、人聲如沸稍味。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)仲闽。三九已至,卻和暖如春僵朗,著一層夾襖步出監(jiān)牢的瞬間赖欣,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工验庙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留顶吮,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓粪薛,卻偏偏與公主長(zhǎng)得像悴了,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • 1湃交、TCP狀態(tài)linux查看tcp的狀態(tài)命令:1)熟空、netstat -nat 查看TCP各個(gè)狀態(tài)的數(shù)量2)、lso...
    北辰青閱讀 9,412評(píng)論 0 11
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理搞莺,服務(wù)發(fā)現(xiàn)息罗,斷路器,智...
    卡卡羅2017閱讀 134,633評(píng)論 18 139
  • 對(duì)TCP/IP才沧、UDP迈喉、Socket編程這些詞你不會(huì)很陌生吧?隨著網(wǎng)絡(luò)技術(shù)的發(fā)展温圆,這些詞充斥著我們的耳朵挨摸。那么我想...
    yuantao123434閱讀 5,454評(píng)論 1 97
  • 當(dāng)思潮漫天涌, 其實(shí)已超越時(shí)間岁歉, 我是越光者得运, 我以我之思, 于此世 長(zhǎng)留锅移。
    碎飄啊閱讀 150評(píng)論 0 0