久久99精品久久久久久琪琪,久久人人爽人人爽人人片亞洲,熟妇人妻无码中文字幕,亚洲精品无码久久久久久久

網絡編程常見問題總結

時間:2019-05-12 03:57:18下載本文作者:會員上傳
簡介:寫寫幫文庫小編為你整理了多篇相關的《網絡編程常見問題總結》,但愿對你工作學習有幫助,當然你在寫寫幫文庫還可以找到更多《網絡編程常見問題總結》。

第一篇:網絡編程常見問題總結

網絡編程常見問題總結

網絡編程常見問題總結 串講(一)

網絡編程常見問題總結

在網絡程序中遇到的一些問題進行了總結, 這里主要針對的是我們常用的TCP socket相關的總結,可能會存在錯誤,有任何問題歡迎大家提出.對于網絡編程的更多詳細說明建議參考下面的書籍

《UNIX網絡編程》 《TCP/IP 詳解》 《Unix環(huán)境高級編程》

非阻塞IO和阻塞IO:

在網絡編程中對于一個網絡句柄會遇到阻塞IO和非阻塞IO的概念, 這里對于這兩種socket先做一下說明

基本概念:

socket的阻塞模式意味著必須要做完IO操作(包括錯誤)才會返回。非阻塞模式下無論操作是否完成都會立刻返回,需要通過其他方式來判斷具體操作是否成功。

設置:

一般對于一個socket是阻塞模式還是非阻塞模式有兩種方式 fcntl設置和recv,send系列的參數(shù).fcntl函數(shù)可以將一個socket句柄設置成非阻塞模式:

flags = fcntl(sockfd, F_GETFL, 0);fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);設置之后每次的對于sockfd的操作都是非阻塞的

recv, send函數(shù)的最后有一個flag參數(shù)可以設置成MSG_DONTWAIT臨時將sockfd設置為非阻塞模式,而無論原有是阻塞還是非阻塞。recv(sockfd, buff, buff_size, MSG_DONTWAIT);send(scokfd, buff, buff_size, MSG_DONTWAIT);區(qū)別:

讀:

讀本質來說其實不能是讀,在實際中, 具體的接收數(shù)據不是由這些調用來進行,是由于系統(tǒng)底層自動完成的,read也好,recv也好只負責把數(shù)據從底層緩沖copy到我們指定的位置.對于讀來說(read, 或者 recv),在阻塞條件下如果沒有發(fā)現(xiàn)數(shù)據在網絡緩沖中會一直等待,當發(fā)現(xiàn)有數(shù)據的時候會把數(shù)據讀到用戶指定的緩沖區(qū),但是如果這個時候讀到的數(shù)據量比較少,比參數(shù)中指定的長度要小,read并不會一直等待下去,而是立刻返回。read的原則是數(shù)據在不超過指定的長度的時候有多少讀多少,沒有數(shù)據就會一直等待。所以一般情況下我們讀取數(shù)據都需要采用循環(huán)讀的方式讀取數(shù)據,一次read完畢不能保證讀到我們需要長度的數(shù)據,read完一次需要判斷讀到的數(shù)據長度再決定是否還需要再次讀取。在非阻塞的情況下,read的行為是如果發(fā)現(xiàn)沒有數(shù)據就直接返回,如果發(fā)現(xiàn)有數(shù)據那么也是采用有多少讀多少的進行處理.對于讀而言,阻塞和非阻塞的區(qū)別在于沒有數(shù)據到達的時候是否立刻返回.

recv中有一個 MSG_WAITALL的參數(shù) recv(sockfd, buff, buff_size, MSG_WAITALL), 在正常情況下 recv是會等待直到讀取到buff_size長度的數(shù)據,但是這里的WAITALL也只是盡量讀全,在有中斷的情況下recv還是可能會 被打斷,造成沒有讀完指定的buff_size的長度。所以即使是采用recv + WAITALL參數(shù)還是要考慮是否需要循環(huán)讀取的問題,在實驗中對于多數(shù)情況下recv還是可以讀完buff_size,所以相應的性能會比直接read 進行循環(huán)讀要好一些。不過要注意的是這個時候的sockfd必須是處于阻塞模式下,否則WAITALL不能起作用。

寫:

寫的本質也不是進行發(fā)送操作,而是把用戶態(tài)的數(shù)據copy到系統(tǒng)底層去,然后再由系統(tǒng)進行發(fā)送操作,返回成功只表示數(shù)據已經copy到底層緩沖,而不表示數(shù)據以及發(fā)出,更不能表示對端已經接收到數(shù)據.對于write(或 者send)而言,在阻塞的情況是會一直等待直到write完全部的數(shù)據再返回.這點行為上與讀操作有 所不同,究其原因主要是讀數(shù)據的時候我們并不知道對端到底有沒有數(shù)據,數(shù)據是在什么時候結束發(fā)送的,如果一直等待就可能會造成死循環(huán),所以并沒有去進行這方面的處理;而對于write, 由于需要寫的長度是已知的,所以可以一直再寫,直到寫完.不過問題是write是可能被打斷造成write一次只write一部分數(shù)據, 所以write的過程還是需要考慮循環(huán)write, 只不過多數(shù)情況下一次write調用就可能成功.非阻塞寫的情況下,是采用可以寫多少就寫多少的策略.與讀不一樣的地方在于,有多少讀多少是由網絡發(fā)送的那一端是否有數(shù)據傳輸?shù)綖闃藴剩菍τ诳梢詫懚嗌偈怯杀镜氐木W絡堵塞情況為標準的,在網絡阻塞嚴重的時候,網絡層沒有足夠的內存來進行寫操作,這時候就會出現(xiàn)寫不成功的情況,阻塞情況下會盡可能(有可能被中斷)等待到數(shù)據全部發(fā)送完畢,對于非阻塞的情況就是一次寫多少算多少,沒有中斷的情況下也還是會出現(xiàn)write到一部分的情況.網絡編程常見問題總結 串講(二)

超時控制:

對于網絡IO,我們一般情況下都需要超時機制來避免進行操作的線程被handle住,經典的做法就是采用select+非阻塞IO進行判斷,select在超時時間內判斷是否可以讀寫操作,然后采用非堵塞讀寫,不過一般實現(xiàn)的時候讀操作不需要設置為非堵塞,上面已經說過讀操作只有在沒有數(shù)據的 時候才會阻塞,select的判斷成功說明存在數(shù)據,所以即使是阻塞讀在這種情況下也是可以做到非阻塞的效果,就沒有必要設置成非阻塞的情況了.

這部分的代碼可以參考ullib中ul_sreado_ms_ex和ul_swriteo_ms_ex.

采用ul_sreado_ms_ex讀數(shù)據也是不能保證返回大于0就一定讀到指定的數(shù)據長度, 對于讀寫操作, 都是需要判斷返回的讀長度或者寫長度是否是需要的長度, 不能簡單的判斷一下返回值是否小于0.對于ul_sreado_ms_ex的情況如果出現(xiàn)了發(fā)送端數(shù)據發(fā)送一半就被close掉的情況就有可能導致接收端讀不到完整的數(shù)據包.errno 只有在函數(shù)返回值為負的時候才有效,如果返回0或者大于0的數(shù), errno 的結果是無意義的.有些時候 會出現(xiàn)read到0,但是我們認為是錯誤的情況然后輸出errno造成誤解,一般建議在這種情況要同時輸出返回值和errno的結果,有些情況由于只有errno造成了對于問 題的判斷失誤。

長連接和短連接的各種可能的問題及相應的處理

這里主要是發(fā)起連接的客戶端的問題,這里列出的問題主要是在采用同步模型的情況下才會存在的問題.短連接:

采用短連接的情況一般是考慮到下面的一些問題: 后端服務的問題, 考慮最簡單的情況下一個線程一個連接, 如果這個連接采用了長連接那么就需要我們處理連接的線程和后端保持一一對應,然后按照某些原則進行處理(n對n的關系), 但由于一方面服務器可能增加,這樣導致需要前后端保持一致,帶來了更多的麻煩,另一方面線程數(shù)上不去對應處理能力也會產生影響,而短連接每次連接的時候只 需要關注當前的機器,問題相對會少一些.其實這個問題可以采用連接池的方式來解決,后面會提到.不需要考慮由于異常帶來的臟數(shù)據。負載均衡方面可以簡單考慮, 無論線程數(shù)是多少還是后端服務器的數(shù)量是多少都沒有關系, 每次考慮單個連接就可以了.當然如果負載邏輯簡單,并且機器相對固定,一個線程一個長連接問題也不大.規(guī)避一些問題, 在過去有些情況下出現(xiàn)長連接大延時,數(shù)據沒響應等問題, 測試的時候發(fā)現(xiàn)換短連接問題就解決了,由于時間關系就沒有再繼續(xù)追查, 事實上這些問題現(xiàn)在基本上都已經定位并且有相關的解決方案了.不足:

效率不足, 由于連接操作一般會有50ns~200ns的時間消耗,導致短連接需要消耗更多的時間會產生TIME_WAIT問題,需要做更多的守護

長連接:

長連接相比短連接減少了連接的時間消耗, 可以承受更高的負載.但在使用的時候需要考慮一些問題臟數(shù)據, 在一些特殊情況(特別是邏輯錯誤的情況下)會存在一些我們并不需要的數(shù)據.這個時候的處理比較安全的方式是一旦檢測到就關閉連接, 檢測的方式在在發(fā)起請求前用前面為什么socket寫錯誤,但用recv檢查依然成功? 介紹的方式進行檢查.不過有些程序會采用繼續(xù)讀把所有不需要的數(shù)據讀完畢(讀到 EAEGIN), 不過這種方式過分依賴邏輯了,存在了一定的風險.不如直接斷開來的簡單 后端連接, 前面也提到了 在這種情況我們一般會采用連接池的方式來解決問題比如(public/connectpool中就可以維護不同的連接,使每個線程都可以均勻的獲取到句 柄)服務端的處理這個時候需要考慮連接的數(shù)量,簡單的方式就是一個長連接一個線程, 但是線程也不能無限增加(增加了,可能造成大量的上下文切換使的性能下降).我們一般在長連接的情況采用pendingpool的模型, 通過一個異步隊列來緩沖, 這樣不需要考慮客戶端和服務端的線程數(shù)問題,可以任意配置(可以通過線下測試選擇合適的線程數(shù))

一些特殊的問題, 主要是長連接的延時 在后面的FAQ中會有詳細的說明.一般來說,對于我們多數(shù)的內部業(yè)務邏輯都是可以采用長連接模式,不會產生太多的問題.網絡編程常見問題總結 串講(三)

主要線程模型優(yōu)缺點和注意事項

這里所列出的線程模型,目前在我們的public/ub下都有相關的實現(xiàn),在 ubFAQ中也有相關的說明,這里主要針對這些模 型的使用做相關的說明

最簡單的線程模型 同時啟動多個線程,每個線程都采用accept的方式進行阻塞獲取連接(具體實現(xiàn)上一般是先select在accept, 一方面規(guī)避低內核的驚群效應,另一方面可以做到優(yōu)雅退出).多個線程競爭一個連接, 拿到連接的線程就進行自己的邏輯處理, 包括讀寫IO全部都在一個線程中進行.短連接每次重新accept, 長連接,第一次的時候accept然后反復使用.一般來說在總連接數(shù)很少的情況下效果會比較好,相對適用于少量短連接(可以允許比線程數(shù)多一些)和不超過線程總數(shù)的長連接(超過的那些連接,除非 accept的連接斷開,否則不可能會有線程對它進行accept).但如果同一時候連接數(shù)過多會造成沒有工作線程與客戶端進行連接,客戶端會出現(xiàn)大量的連接失敗, 因為這個時候線程可能存在不能及時accept造成超時問題, 在有重試機制的情況下可能導致問題更糟糕.有些程序在出現(xiàn)幾次超時之后會長時間一直有連接超時往往就是在這種情況下發(fā)生的.這種模型的最大優(yōu)點在于編寫簡單, 在正常情況下工作效果不錯.在public/ub中的xpool就是屬于這種模型,建議針對連接數(shù)少的服務進行使用,比如一些一對一的業(yè)務邏輯.生產者消費者模型

普通線程模型在長連接方面存在使用限制(需要對于線程數(shù)進行變化, 而線程又不是無限的), 短連接在處理同時大量連接(比如流量高峰期)的時候存在問題.生產者消費者模型是可以把這種影響減少.對于有數(shù)據的活動連接放到異步隊列中, 其他線程競爭這個隊列獲取句柄然后進行相關的操作.由于accept是專門的線程進行處理, 出現(xiàn)被handle的情況比較少,不容易出現(xiàn)連接失敗的情況.在大流量的情況下有一定的緩沖,雖然有些請求會出現(xiàn)延時,但只要在可以接受的范圍內,服務還 是可以正常進行.一般來說隊列的長度主要是考慮可以接受的延時程度.這種模式也是我們現(xiàn)在許多服務比較常用的模型.可以不用關心客戶端和服務的線程數(shù)對應關系,業(yè)務邏輯上也是比較簡單的。

但這種模式在編程的 時候,對于長連接有一個陷阱,判斷句柄是否可讀寫以前一般采用的是select, 如果長連接的連接數(shù)比工作線程還少,當所有的連接都被處理了,有連接需要放回pool中,而這個時候如果正常建立連接的監(jiān)聽線程正好處于select狀 態(tài),這個時候必須要等到 select超時才能重新將連接放入select中進行監(jiān)聽,因為這之前被放入select進行監(jiān)聽的處理socket為空,不會有響應,這個時候由于時 間的浪費造成l長連接的性能下降。一般來說某個連接數(shù)少,某個連接特別活躍就可能造成問題.過去的一些做法是控制連接數(shù)和服務端的工作線程數(shù)以及通過監(jiān)聽一個管道fd,在工作線程結束每次都激活這個fd跳出這次select來控制。現(xiàn)在的2.6 內核中的epoll在判斷可讀寫的時候不會存在這個問題(epoll在進行監(jiān)聽的時候,其它線程放入或者更改, 在epoll_wait的時候是可以馬上激活的), 我們現(xiàn)在的服務多采用epoll代替select來解決這個, 但是主要的邏輯沒有變化.ub_server中epool和public/ependingpool都是采用種模式

異步模型

這里只做一些簡單的介紹。上 面兩者模型本質都是同步的處理業(yè)務邏輯,在一個線程中處理了讀請求,業(yè)務邏輯和寫回響應三個過程(很多業(yè)務更復雜,但是都是可以做相應的拆封的), 但是讀和寫這兩個IO的處理往往需要阻塞等待, 這樣造成了線程被阻塞, 如果要應付慢連接(比如外圍抓取等待的時間是秒級的甚至更多), 在等待的時候其實CPU沒有干多少事情, 這個時候就造成了浪費.一種考慮是增加線程數(shù),通過提高并發(fā)來解決這個問題, 但是我們目前的線程數(shù)還是有限的,不可能無限增加.而且線程的增加會帶來cpu對于上下文切換的代價,另一方面多個線程從一個隊列中獲取可用連接, 這里存在互斥線程多的時候會導致性能下降,當然這里可以通過把一個隊列改多隊列減少互斥來實現(xiàn).引入異步化的處理, 就是把對于IO的等待采用IO復用的方式,專門放入到一個或者若干個線程中去, 處理主邏輯的程序可以被釋放出來, 只有在IO處理完畢才進行處理, 這樣可以提高CPU的使用率,減少等待的時間.一般情況下幾個線程(一般和CPU的核數(shù)相當)可以應付很大的流量請求 public/kylin , ub/ub(ub事件模型)都是基于純異步思想的異步框架。而ub中的appool是簡化版本將原本ub框架中網絡IO處理進行了異步化,不過目前只支持 采用nshead頭的模式。網絡編程常見問題總結 串講(四)

為什么網絡程序會沒有任何預兆的就退出了

一般情況都是沒有設置忽略PIPE信號,在我們的環(huán)境中當網絡觸發(fā)broken pipe(一般情況是write的時候,沒有write完畢,接受端異常斷開了),系統(tǒng)默認的行為是直接退出。在我們的程序中一般都要在啟動的時候加上 signal(SIGPIPE, SIG_IGN);來強制忽略這種錯誤

write出去的數(shù)據, read的時候知道長度嗎?

嚴格來說, 交互的兩端, 一端write調用write出去的長度, 接收端是不知道具體要讀多長的.這里有幾個方面的問題

write 長度為n的數(shù)據, 一次write不一定能成功(雖然小數(shù)據絕大多數(shù)都會成功), 需要循環(huán)多次write,write雖然成功,但是在網絡中還是可能需要拆包和組包, write出來的一塊數(shù)據, 在接收端底層接收的時候可能早就拆成一片一片的多個數(shù)據包.TCP層中對于接收到的數(shù)據都是把它們放到緩沖中, 然后read的時候一次性copy, 這個時候是不區(qū)分一次write還是多次write的。所以對于網絡傳輸中 我們不能通過簡單的read調用知道發(fā)送端在這次交互中實際傳了多少數(shù)據.一般來說對于具體的交互我們一般采取下面的方式來保證交互的正確,事先約定好長度, 雙方都采用固定長度的數(shù)據進行交互, read, write的時候都是讀取固定的長度.但是這樣的話升級就必須考慮兩端同時升級的問題。特殊的結束符或者約定結束方式, 比如http頭中采用連續(xù)的/r/n來做頭部的結束標志.也有一些采用的是短連接的方式, 在read到0的時候,傳輸變長數(shù)據的時候一般采用定長頭部+變長數(shù)據的方式, 這個時候在定長的頭部會有一個字段來表示后面的變長數(shù)據的長度, 這種模式下一般需要讀取兩次確定長度的數(shù)據.我們現(xiàn)在內部用的很多都是這樣的模式.比如public/nshead就是這樣處理, 不過nshead作為通用庫另外考慮了采用 通用定長頭+用戶自定義頭+變長數(shù)據的接口。

總的來說read讀數(shù) 據的時候不能只通過read的返回值來判斷到底需要讀多少數(shù)據, 我們需要額外的約定來支持, 當這種約定存在錯誤的時候我們就可以認為已經出現(xiàn)了問題.另外對于write數(shù)據來說, 如果相應的數(shù)據都是已經準備好了那這個時候也是可以把數(shù)據一次性發(fā)送出去,不需要調用了多次write.一般來說write次數(shù)過多也會對性能產生影響,另一個問題就是多次連續(xù)可能會產生延時問題,這個參看下面有關長連接延時的部分問題.小提示

上面提到的都是TCP的情況, 不一定適合其他網絡協(xié)議.比如在UDP中 接收到連續(xù)2個UDP包, 需要分別讀來次才讀的出來, 不能像TCP那樣,一個read可能就可以成功(假設buff長度都是足夠的)。如何查看和觀察句柄泄露問題 一般情況句柄只有1024個可以使用,所以一般情況下比較容易出現(xiàn),也可以通過觀察/proc/進程號/fd來觀察。

另外可以采用valgrind來檢查,valgrind參數(shù)中加上--track-fds = yes 就可以看到最后退出的時候沒有被關閉的句柄,以及打開句柄的位置

為什么socket寫錯誤,但用recv檢查依然成功?

首先采用recv檢查連接的是基于我們目前的一個請求一個應答的情況對于客戶端的請求,邏輯一般是這樣 建立連接->發(fā)起請求->接受應答->長連接繼續(xù)發(fā)請求

recv檢查一般是這樣采用下面的方式: ret = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);通過判斷ret 是否為-1并且errno是EAGAIN 在非堵塞方式下如果這個時候網絡沒有收到數(shù)據, 這個時候認為網絡是正常的。這是由于在網絡交換模式下 我們作為一個客戶端在發(fā)起請求前, 網絡中是不應該存在上一次請求留下來的臟數(shù)據或者被服務端主動斷開(服務端主動斷開會收到FIN包,這個時候是recv返回值為0), 異常斷開會返回錯誤.當然這種方式來判斷連接是否存在并不是非常完善,在特殊的交互模式(比如異步全雙工模式)或者延時比較大的網絡中都是存在問題的,不過對于我們目前內網中的交互模式還是基本適用的.這種方式和socket寫錯誤并不矛盾, 寫數(shù)據超時可能是由于網慢或者數(shù)據量太大等問題, 這時候并不能說明socket有錯誤, recv檢查完全可能會是正確的.一般來說遇到socket錯誤,無論是寫錯誤還讀錯誤都是需要關閉重連.為什么接收端失敗,但客戶端仍然是write成功

這個是正常現(xiàn)象,write數(shù)據成功不能表示數(shù)據已經被接收端接收導致,只能表示數(shù)據已經被復制到系統(tǒng)底層的緩沖(不一定發(fā)出), 這個時候的網絡異常都是會造成接收端接收失敗的.長連接的情況下出現(xiàn)了不同程度的 延時 在一些長連接的條件下, 發(fā)送一個小的數(shù)據包,結果會發(fā)現(xiàn)從數(shù)據write成功到接收端需要等待一定的時間后才能接收到, 而改成短連接這個現(xiàn)象就消失了(如果沒有消失,那么可能網絡本身確實存在延時的問題,特別是跨機房的情況下)在長連接的處理中出現(xiàn)了延時,而且時間固定,基本都是40ms, 出現(xiàn)40ms延時最大的可能就是由于沒有設置TCP_NODELAY 在長連接的交互中,有些時候一個發(fā)送的數(shù)據包非常的小,加上一個數(shù)據包的頭部就會導致浪費,而且由于傳輸?shù)臄?shù)據多了,就可能會造成網絡擁塞的情況, 在系統(tǒng)底層默認采用了Nagle算法,可以把連續(xù)發(fā)送的多個小包組裝為一個更大的數(shù)據包然后再進行發(fā)送.但是對于我們交互性的應用程序意義就不大了,在這種情況下我們發(fā)送一個小數(shù)據包的請求,就會立刻進行等待,不會還有后面的數(shù)據包一起發(fā)送, 這個時候Nagle算法就會產生負作用,在我們的環(huán)境下會產生40ms的延時,這樣就會導致客戶端的處理等待時間過長, 導致程序壓力無法上去.在代碼中無論是服務端還是客戶端都是建議設置這個選項,避免某一端造成延時。所以對于長連接的情況我們建議都需要設置TCP_NODELAY, 在我們的ub框架下這個選項是默認設置的.小提示:

對于服務端程序而言, 采用的模式一般是

bind-> listen-> accept, 這個時候accept出來的句柄的各項屬性其實是從listen的句柄中繼承, 所以對于多數(shù)服務端程序只需要對于listen進行監(jiān)聽的句柄設置一次TCP_NODELAY就可以了,不需要每次都accept一次.設置了NODELAY選項但還是時不時出現(xiàn)10ms(或者某個固定值)的延時 這種情況最有可能的就是服務端程序存在長連接處理的缺陷.這種情況一般會發(fā)生在使用我們的pendingpool模型(ub中的cpool)情況下,在 模型的說明中有提到.由于select沒有及時跳出導致一直在浪費時間進行等待.上面的2個問題都處理了,還是發(fā)現(xiàn)了40ms延時?

協(xié)議棧在發(fā)送包的時候,其實不僅受到TCP_NODELAY的影響,還受到協(xié)議棧里面擁塞窗口大小的影響.在連接發(fā)送多個小數(shù)據包的時候會導致數(shù)據沒有及時發(fā)送出去.這里的40ms延時其實是兩方面的問題: 對于發(fā)送端, 由于擁塞窗口的存在,在TCP_NODELAY的情況,如果存在多個數(shù)據包,后面的數(shù)據包可能會有延時發(fā)出的問題.這個時候可以采用 TCP_CORK參數(shù), TCP_CORK 需要在數(shù)據write前設置,并且在write完之后取消,這樣可以把write的數(shù)據發(fā)送出去(要注意設置TCP_CORK的時候不能與TCP_NODELAY混用,要么不設置TCP_NODELAY要么就先取消TCP_NODELAY)但是在做了上 面的設置后可能還是會導致40ms的延時, 這個時候如果采用tcpdump查看可以注意是發(fā)送端在發(fā)送了數(shù)據包后,需要等待服務端的一個ack后才會再次發(fā)送下一個數(shù)據包,這個時候服務端出現(xiàn)了延 時返回的問題.對于這個問題可以通過設置server端TCP_QUICKACK選項來解決.TCP_QUICKACK可以讓服務端盡快的響應這個ack包.這個問題的主要原因比較復雜,主要有下面幾個方面

當TCP協(xié)議棧收到數(shù)據的時候, 是否進行ACK響應(沒有響應是不會發(fā)下一個包的),在我們linux上返回ack包是下面這些條件中的一個接收的數(shù)據足夠多

處于快速回復模式(TCP_QUICKACK)

存在亂序的包,如果有數(shù)據馬上返回給發(fā)送端,ACK也會一起跟著發(fā)送

如果都不滿足上面的條件,接收方會延時40ms再發(fā)送ACK,這個時候就造成了延時。

但是對于上面的情況即使是采用TCP_QUICKACK,服務端也不能保證可以及時返回ack包,因為快速回復模式在一些情況下是會失效(只能通過修改內核來實現(xiàn))目前的解決方案只能是通過修改內核來解決這個問題,STL的同學在 內核中增加了參數(shù)可以控制這個問題。

會出現(xiàn)這種情況的主要是連接發(fā)送多個小數(shù)據包或者采用了一些異步雙工的編程模式,主要的解決方案有下面幾種對于連續(xù)的多個小數(shù)據包,盡量把他們打到一個buffer中間, 不過會有內存復制的問題(采用writev方式發(fā)送多個小數(shù)據包,不過writev也存在一個問題就是發(fā)送的數(shù)據包個數(shù)有限制,如果超過了IOV_MAX(我們的限制一般是1024),依然可能會出現(xiàn)問題,因為writev只能保證在IOV_MAX范圍內的數(shù)據是按照連續(xù)發(fā)送的。

writev或者大buffer的方式在異步雙工模式下是無法工作,這個時候只能通過系統(tǒng)方式來解決。客戶端 不設置TCP_NODELAY選項,發(fā)送數(shù)據前先打開TCP_CORK選項,發(fā)送完后再關閉TCP_CORK,服務端開啟TCP_QUICKACK選項

采用STL修改的內核5-6-0-0,打開相關參數(shù)。

網絡編程常見問題總結 串講(五)

TIME_WAIT有什么樣的影響?

對于TIME_WAIT的出現(xiàn)具體可以參考<>中的章節(jié),總的來說對于一個已經建立的連接如果是主動 close, 那么這個連接的端口(注意:不是socket)就會進入到TIME_WAIT狀態(tài),在我們的機器上需要等待60s的時間(有些書上可能提到的是 2MSL,1MSL為1分鐘,但我們的linux實現(xiàn)是按照1分鐘的).在這一段時間內,這個端口將不會被釋放,新建立的連接就無法使用這個端口(連接的時候會報Cannot assign requested address的錯誤).可以通過/proc/sys/net/ipv4/ip_local_port_range看到可用端口的范圍,我們的機器上一般是32768--61000,不足3W個,這樣的結果就是導致如果出現(xiàn)500/s的短連接請求,就會導致端口不夠用連接不上。這種情況一般修改系統(tǒng)參數(shù)tcp_tw_reuse或者在句柄關閉前設置SO_LINGER選項來解決,也可以通過增大 ip_local_port_range來緩解,設置SO_LINGER后句柄會被系統(tǒng)立刻關閉,不會進入TIME_WAIT狀態(tài),不過在一些大壓力的情況還是有可能出現(xiàn)連接的替身,導致數(shù)據包丟失。系統(tǒng)參數(shù)/proc/sys/net/ipv4/tcp_tw_reuse設為1 會復用TIME_WAIT狀態(tài)socket,如果開啟,客戶端在調用connect調用時,會自動復用TIME_WAIT狀態(tài)的端口,相比 SO_LINGER選項更加安全。

對于服務器端如果出現(xiàn)TIME_WAIT狀態(tài),是不會產生端口不夠用的情況,但是TIME_WAIT過多在服務器端還是會占用一定的內存資源,在/proc/sys/net/ipv4/tcp_max_xxx 中我們可以系統(tǒng)默認情況下的所允許的最大TIME_WAIT的個數(shù),一般機器上都是180000, 這個對于應付一般程序已經足夠了.但對于一些壓力非常大的程序而言,這個時候系統(tǒng)會不主動進入TIME_WAIT狀態(tài)而且是直接跳過,這個時候如果去看 dmsg中的信息會看到 “TCP: time wait bucket table overflow” , 一般來說這種情況是不會產生太多的負面影響, 這種情況下后來的socket在關閉時不會進入TIME_WAIT狀態(tài),而是直接發(fā)RST包, 并且關閉socket.不過還是需要關注為什么會短時間內出現(xiàn)這么大量的請求。

小提示: 如果需要設置SO_LINGER選項, 需要在FD連接上之后設置才有效果

: O% B: j3 o/ A

什么情況下會出現(xiàn)CLOSE_WAIT狀態(tài)?

一般來說,連接的一端在被動關閉的情況下,已經接收到FIN包(對端調用close)后,這個時候如果接收到FIN包的一端沒有主動close就會出 現(xiàn)CLOSE_WAIT的情況。一般來說,對于普通正常的交互,處于CLOSE_WAIT的時間很短,一般的邏輯是檢測到網絡出錯,馬上關閉。但是在一些情況下會出現(xiàn)大量的CLOS_WAIT, 有的甚至維持很長的時間,這個主要有幾個原因:

沒有正確處理網絡異常,特別是read 0的情況,一般來說被動關閉的時候會出現(xiàn)read 返回0的情況。一般的處理的方式在網絡異常的情況下就主動關閉連接句柄泄露了,句柄泄露需要關閉的連接沒有關閉而對端又主動斷開的情況下也會出現(xiàn)這樣的問 題。連接端采用了連接池技術,同時維護了較多的長連接(比如ub_client, public/connectpool),同時服務端對于空閑的連接在一定的時間內會主動斷開(比如ub_server, ependingpool都有這樣的機制).如果服務端由于超時或者異常主動斷開,客戶端如果沒有連接檢查的機制,不會主動關閉這個連接,比如ub_client的機制就是長連接建立后除非到使用的時候進行連接檢查,否則不會主動斷開連接。這個時候在建立連接的一端就會出現(xiàn)CLOSE_WAIT狀態(tài)。這個時候的狀態(tài)一般來說是安全(可控的,不會超過最大連接數(shù)).在com 的connectpool 2中這種情況下可以通過打開健康檢查線程進行主動檢查,發(fā)現(xiàn)斷開后主動close.網絡編程常見問題總結 串講(六)順序發(fā)送數(shù)據,接收端出現(xiàn)亂序接收到的情況:

網絡壓力大的情況下,有時候會出現(xiàn),發(fā)送端是按照順序發(fā)送, 但是接收端接收的時候順序不對.一般來說在正常情況下是不會出現(xiàn)數(shù)據順序錯誤的情況, 但某些異常情況還是有可能導致的.在我們的協(xié)議棧中,服務端每次建立連接其實都是從accpet所在的隊列中取出一個已經建立的fd, 但是在一些異常情況下,可能會出現(xiàn)短時間內建立大量連接的情況, accept的隊列長度是有限制,這里其實有兩個隊列,一個完成隊列另一個是未完成隊列,只有完成了三次握手的連接會放到完成隊列中。如果在短時間內accept中的fd沒有被取出導致隊 列變滿,但未完成隊列未滿,這個時候連接會在未完成隊列中,對于發(fā)起連接的一端來說表現(xiàn)的情況是連接已經成功,但實際上連接本身并沒有完成,但這個時候我們依然可以發(fā)起寫操作并且成 功,只是在進行讀操作的時候,由于對端沒有響應會造成讀超時。對于超時的情況我們一般就把連接直接close關閉了,但是句柄雖然被關閉了,但是由于TIME_WAIT狀態(tài)的存在,TCP還是會進行重傳。在重傳的時候,如果完成隊列有句柄被處理,那么此時會完成三次握手建立連接,這個時候服務端照樣會進行正常的處理(不過在寫響應的 時候可能會發(fā)生錯誤)。從接收上看,由于重傳成功的情況我們不能控制,對于接收端來說就可能出現(xiàn)亂序的情況。完成隊列的長度和未完成隊列的長度由listen時候的baklog決定((ullib庫中ul_tcplisten的最后一個參數(shù)),在我們的 linux環(huán)境中baklog是完成隊列的長度,baklog * 1.5是兩個隊列的總長度(與一些書上所說的兩個隊列長度不超過baklog有出入).兩個隊列的總長度最大值限制是128, 既使設置的結果超過了128也會被自動改為128。128這個限制可以通過 系統(tǒng)參數(shù) /proc/sys/net/core/somaxconn 來更改, 在我們 5-6-0-0 內核版本以后,STL將其提高到2048.另外客戶端也可以考慮使用SO_LINGER參數(shù)通過強制關閉連接來處理這個問題,這樣在close以后就不啟用重傳機制。另外的考慮就是對重試機制根據 業(yè)務邏輯進行改進。

連接偶爾出現(xiàn)超時有哪些可能?

主要幾個方面的可能

服務端確實處理能力有限,cpu idel太低, 無法承受這樣的壓力,或者 是更后端產生問題

accept隊列設置過小,而連接又特別多,需要增大baklog,建議設置為128這是我們linux系統(tǒng)默認的最大值 由/proc/sys/net/core/somaxconn決定,可以通過修改這個值來增大(由于很多書上這個地方設置為5,那個其實是4.2BSD支 持的最大值, 而不是現(xiàn)在的系統(tǒng), 不少程序中都直接寫5了,其實可以更大, 不過超過128還是按照128來算)

程序邏輯問題導致accept處理不過來, 導致連接隊列中的連接不斷增多直到把accept隊列撐爆, 像簡單的線程模型(每個線程一個accept), 線程被其他IO一類耗時操作handle,導致accept隊列被撐爆, 這個時候默認的邏輯是服務端丟棄數(shù)據包,導致client端出現(xiàn)超時,但是可以通過打開/proc/sys/net/ipv4/tcp_abort_on_overflow開關讓服務端立刻返回失敗

當讀超時的時候(或者其他異常), 我們都會把連接關閉,進行重新連接,這樣的行為如果很多,也可能造成accept處理不過來

異常情況下,設置了SO_LINGER造成連接的ack包被丟失, 雖然情況極少,但大壓力下還是有存在的.當然還是有可能是由于網絡異常或者跨機房耗時特別多產生的, 這些就不是用戶態(tài)程序可以控制的。

另外還有發(fā)現(xiàn)有些程序采用epoll的單線模式, 但是IO并沒有異步化,而是阻塞IO,導致了處理不及時.網絡編程常見問題總結 串講(七)

listen的時候的backlog有什么影響?

backlog代表連接的隊列, 這里對于內核中其實會維護2個隊列

未完成隊列, 這個是服務器端接收到連接請求后會先放到這里(第一次握手)這個時候端口會處于SYN_RCVD狀態(tài)

已完成隊列,完成三次握手的連接會放到這里,這個時候才是連接建立

在我們 的linux環(huán)境中backlog 一般是被定義為已完成隊列的長度,為完成隊列一般是按照以完成隊列長度的一半來取,backlog為5,那么已完成隊列為5,未完成隊列為3,總共是8個。如果這里的8個都被占滿了,那么后面的連接就會失敗,這里的行為可以由 /proc/sys/net/ipv4/tcp_abort_on_overflow 參數(shù)控制,這個參數(shù)打開后隊列滿了會發(fā)送RST包給client端,client端會看到Connection reset by peer的錯誤(線上部分內核打開了這個參數(shù)), 如果是關閉的話, 服務端會丟棄這次握手, 需要等待TCP的自動重連, 這個時間一般比較長, 默認情況下第一次需要3秒鐘, 由于我們的連接超時一般都是很小的, client采用ullib庫中的超時連接函數(shù), 那么會發(fā)現(xiàn)這個時候連接超時了。

長連接和短連接混用是否會有問題?

雖然這種方式并不合適,但嚴格來說如果程序中做好相關的守護操作(包括一些情況下系統(tǒng)參數(shù)的調整)是不會出現(xiàn)問 題,基本來說在長短連接混用情況下出現(xiàn)的問題都是由于我們的程序存在不同程度上的缺陷造成的.

可能出現(xiàn)的問題:

只要有一端采用了短連接,那么就可以認為總體是短連接模式。

服務端長連接,客戶端短連接

客戶端主動關 閉,服務端需要接收到close的FIN包,read返回0 后才知道客戶端已經被關閉。在這一段時間內其實服務端多維護了一個沒有必要連接的狀態(tài)。在同步模式(pendingpool,ub-xpool, ub-cpool, ub-epool)中由于read是在工作線程中,這個連接相當于線程多做了一次處理,浪費了系統(tǒng)資源。如果是IO異步模式(ub/apool或者使用 ependingpool讀回調)則可以馬上發(fā)現(xiàn),不需要再讓工作線程進行處理

服務端如果采用普通線程模型(ub-xpool)那么在異常情況下FIN包如果沒有及時到達,在這一小段時間內這個處理線程不能處理業(yè)務邏輯。如果出現(xiàn)問題的地方比較多這個時候可能會有連鎖反應短時間內不能相應。

服務端為長連接,對于服務提 供者來說可能早期測試也是采用長連接來進行測試,這個時候accept的baklog可能設置的很小,也不會出現(xiàn)問題。但是一旦被大量短連接服務訪問就可能出現(xiàn)問題。所以建議listen的時候baklog都設置為128, 我們現(xiàn)在的系統(tǒng)支持這么大的baklog沒有什么問題。

每次總是客戶端主動斷開,這導致客戶端出現(xiàn)了TIME_WIAT的狀態(tài),在沒有設置SO_LINGER或者改變系統(tǒng)參數(shù)的情況下,比較容易出現(xiàn)客戶端端口不夠用的情況。

服務端短連接,客戶端長連接這個時候的問 題相對比較少,但是如果客戶端在發(fā)送數(shù)據前(或者收完數(shù)據后)沒有對臟數(shù)據進行檢查,在寫的時候都會出現(xiàn)大量寫錯誤或者讀錯誤,做一次無用的操作,浪費系統(tǒng)資源 一般的建議是采用長連接還是短連接,兩端保持一致,但采用配置的方式并不合適,這個需要在上線的時候檢查這些問題。比較好的方式是把采用長連接還是短連接放到數(shù)據包頭部中。客戶端發(fā)送的時候標記自己是采用 短連接還是長連接,服務端接收到后按照客戶端的情況采取相應的措施,并且告知客戶端。特別的如果服務端不支持長連接,也可以告知客戶端,服務采用了短連 接

要注意的是,如果采用了一些框架或者庫,在read到0的情況下可能會多打日志,這個對性能的影響可能會比較大。

網絡編程常見問題總結 串講(八)

select, epoll使用上的注意

select, epoll實現(xiàn)上的區(qū)別可以參考, 本質上來說 select, poll的實現(xiàn)是一樣的,epoll由于內部采用了樹的結構來維護句柄數(shù),并且使用了通知機制,省去了輪詢的過程,在對于需要大量連接的情況下在CPU上會有一定的優(yōu)勢.

select默認情況下可以支持句柄數(shù) 是1024, 這個可以看/usr/include/bits/typesizes.h 中的__FD_SETSIZE,在我們的編譯機(不是開發(fā)機,是SCMPF平臺的機器)這個值已經被修改為51200, 如果select在處理fd超過1024的情況下出現(xiàn)問題可用檢查一下編譯程序的機器上__FD_SETSIZE是否正確.

epoll在句柄數(shù)的限制沒有像select那樣需要通過改變系統(tǒng)環(huán)境中的宏來實現(xiàn)對更多句柄的支持

另外我們發(fā)現(xiàn)有些程序在使用epoll的時候打開了邊緣觸發(fā)模式(EPOLLET), 采用邊緣觸發(fā)其實是存在風險的,在代碼中需要很小心,避免由于連接兩次數(shù)據到達,而被只讀出一部分的數(shù)據.EPOLLET的本意是在數(shù)據情況發(fā)生變化的時候激活(比如不可讀進入可讀狀態(tài)), 但問題是這個時候如果在一次處理完畢后不能保證fd已經進入了不可讀狀態(tài)(一般來說是讀到EAGIN的情況), 后續(xù)可能就一直不會被激活.一般情況下建議使用EPOLLET模式.一個最典型的問題就是監(jiān)聽的句柄被設置為EPOLLET, 當同時多個連接建立的時候, 我們只accept出一個連接進行處理, 這樣就可能導致后來的連接不能被及時處理,要等到下一次連接才會被激活.小提示: ullib 中常用的ul_sreado_ms_ex,ul_swriteo_ms_ex內部是采用select的機制,即使是在scmpf平臺上編譯出來也還是受到 51200的限制,可用ul_sreado_ms_ex2,和ul_swriteo_ms_ex2這個兩個接口來規(guī)避這個問題,他們內部不是采用 select的方式來實現(xiàn)超時控制的(需要ullib 3.1.22以后版本)

一個進程的socket句柄數(shù)只能是1024嗎?

答案是否定的,一臺機器上可以使用的socket句柄數(shù)是由系統(tǒng)參數(shù) /proc/sys/fs/file-max 來決定的.這里的1024只不 過是系統(tǒng)對于一個進程socket的限制,我們完全可以采用ulimit的參數(shù)把這個值增大,不過增大需要采用root權限,這個不是每個工程師都可以采 用的.所以 在公司內采用了一個limit的程序,我們的所有的機器上都有預裝這個程序,這個程序已經通過了提權可以以root的身份設置ulimit的 結果.使用的時候 limit./myprogram 進行啟動即可,默認是可以支持51200個句柄,采用limit-n num 可以設置實際的句柄數(shù).如果還需要更多的連接就需要用ulimit進行專門的操作.另外就是對于內核中還有一個宏NR_OPEN會限制fd的做大個數(shù),目前這個值是1024*1024

小提示: linux系統(tǒng)中socket句柄和文件句柄是不區(qū)分的,如果文件句柄+socket句柄的個數(shù)超過1024同樣也會出問題,這個時候也需要limit提高句柄數(shù).

ulimit對于非root權限的帳戶而言只能往小的值去設置, 在終端上的設置的結果一般是針對本次shell的, 要還原退出終端重新進入就可以了。

用limit方式啟動,程序讀寫的時候出core?

這個又是另外一個問題,前面已經提到了在網絡程序中對于超時的控制是往往會采用select或者poll的方式.select的時候對于支持的FD其 實是有上限的,可以看/usr/inclue/sys/select.h中對于fd_set的聲明,其實一個__FD_SETSIZE /(8*sizeof(long))的long數(shù)組,在默認情況下__FD_SETSIZE的定義是1024,這個可以看 /usr/include/bits/typesizes.h 中的聲明,如果這個時候這個宏還是1024,那么對于采用select方式實現(xiàn)的讀寫超時控制程序在處理超過1024個句柄的時候就會導致內存越界出 core .我們的程序如果是線下編譯,由于許多開發(fā)機和測試這個參數(shù)都沒有修改,這個時候就會造成出core,其實不一定出core甚至有些情況下會出現(xiàn)有數(shù)據但 還是超時的情況. 但對于我們的SCMPF平臺上編譯出來的程序是正常的,SCMPF平臺上這個參數(shù)已經進行了修改,所以有時會出現(xiàn)QA測試沒問題,RD 自測有問題的情況。

一臺機器最多可以建立多少連接?

理論上來說這個是可以非常多的,取決于可以使用多少的內存.我們的系統(tǒng)一般采用一個四元組來表示一個唯一的連接{客戶端ip, 客戶端端口,服務端ip, 服務端端口}(有些地方算上TCP, UDP表示成5元組), 在網絡連接中對于服務端采用的一般是bind一個固定的端口,然后監(jiān)聽這個端口,在有連接建立的時候進行accept操作,這個時候所有建立的連接都只 用到服務端的一個端口.對于一個唯一的連接在服務端ip和 服務端端口都確定的情況下,同一個ip上的客戶端如果要建立一個連接就需要分別采用不同的端,一臺機器上的端口是有限,最多65535(一個 unsigned char)個,在系統(tǒng)文件/proc/sys/net/ipv4/ip_local_port_range 中我們一般可以看到32768 61000 的結果,這里表示這臺機器可以使用的端口范圍是32768到61000, 也就是說事實上對于客戶端機器而言可以使用的連接數(shù)還不足3W個,當然我們可以調整這個數(shù)值把可用端口數(shù)增加到6W.但是這個時候對于服務端的程序完全不受這個限制因為它都是用一個端口,這個時候服務端受到是連接句柄數(shù)的限制,在上面對于句柄數(shù)的說明已經介紹過了,一個 進程可以建立的句柄數(shù)是由/proc/sys/fs/file-max決定上限和ulimit來控制的.所以這個時候服務端完全可以建立更多的連接,這個 時候的主要問題在于如何維護和管理這么多的連接,經典的一個連接對應一個線程的處理方式這個時候已經不適用了,需要考慮采用一些異步處理的方式來解決, 畢竟線程數(shù)的影響放在那邊

小提示: 一般的服務模式都是服務端一個端口,客戶端使用不同的端口進行連接,但是其實我們也是可以把這個過程倒過來,我們客戶端只用一個端但是服務端確是不同的端 口,客戶端做下面的修改原有的方式 socket分配句柄-> connect 分配的句柄 改為 socket分配句柄->對socket設置SO_REUSEADDR選項->像服務端一樣bind某個端口->connect 就可以實現(xiàn)

不過這種應用相對比較少,對于像網絡爬蟲這種情況可能相對會比較適用,只不過6w連接已經夠多了,繼續(xù)增加的意義不一定那么大就是了.

對于一個不存在的ip建立連接是超時還是馬上返回?

這個要根據情況來看,一般情況connect一個不存在的ip地址,發(fā)起連接的服務需要等待ack的返回,由于ip地址不存在,不會有返回,這個時候會一直等到超時才返回。如 果連接的是一個存在的ip,但是相應的端口沒有服務,這個時候會馬上得到返回,收到一個ECONNREFUSED(Connection refused)的結果。

但是在我們的網絡會存在一些有限制的路由器,比如我們一些機器不允許訪問外網,這個時候如果訪問的ip是一個外網ip(無論是否存在),這個時候也會馬上返回得到一個Network is unreachable的錯誤,不需要等待。

第二篇:《網絡編程課程設計》實習總結

河北科技師范學院歐美學院

實習類型教學實習實習單位河北科技師范學院歐美學院實習起止時間年月 年日 指導教師劉正林所在院(系)信息技術系專業(yè)班級網專1101學生姓名崔珺珺學號

一、實習的基本概況

(一)理論指導

根據實訓內容自行確定

(二)項目情況

項目名稱:企業(yè)門戶網站

開發(fā)環(huán)境:Windows XP

項目分工情況:

我的任務:制作企業(yè)門戶網站框架

二、實習過程或步驟

新建一個記事本文件,開始填寫代碼,我所做的是一家廣告公司的主頁面,所以題目的代碼是這么寫的:XX廣告公司歡迎您!一個公司的主頁必須有其他的鏈接,因為成員比較少,所以我做的比較簡單,我用了

這樣,超鏈接的字體是黑色的,但鼠標指向它以后就是紅色的。

從互聯(lián)網下載一張名為1后綴為JPG的圖片,“XX廣告,行業(yè)的領頭者”下一步編寫代碼,并且將該1.JPG放入主頁所在的文件夾,代碼部分如下:

但是由于知識淺薄,圖片放上去不是非常協(xié)調。

對網頁上半部分的框架表格進行處理,的對字體、字號進行設置,代碼如下:

首頁

公司概況

公司機構

職務設置

工作科研

活動動態(tài)

聯(lián)系客服

圖書資料

客戶服務

了解了一些代碼的含義,比如一個表格可以分成很多行,用表示,比如指的是每行又可以分成許多單元格。

為了使網頁有簡單的交互性在主頁上設置了一個登錄界面和按鈕,代碼如下

用戶名:

密碼:

我連接了一個新建名為1.HTML的網頁,主要是自己弄不太懂有關數(shù)據庫的知識,所以只能簡單的編寫,這樣不論在用戶名、密碼輸入什么,都能跳入第二個頁面。

進行了左側表格框架的設計編寫,代碼如下:

服務導航

管理層

財務室

設計部

后續(xù)處理

服務接待

后勤供給

客戶服務

訂單檔案

人事公告 最后。進行了簡單的后續(xù)處理修改。

三、實習感受

(一)成績與收獲

通過這次網頁制作實習課程,我更加深入的了解了各種代碼語言的作用,從互聯(lián)網上學習了更多的知識。學習制作網頁,必須先從學習HTML語言做起,弄清楚各種語言在制作網頁中的重要作用,通過這次綜合性實驗,我已經可以靈活運用所學知識和技巧制作簡單的網頁。實驗過程中,我盡量充分運用老師教過的知識,對所學知識有一定的鞏固作用,為了做出更好的效果我也翻閱參考了其他的資料,學習到了更多網頁處理的技巧,制作網頁過程中我遇到了不少的問題,通過詢問同學和查找資料都獲得了 解決的辦法,這次實踐對我而言是一個不小的提升,在實踐過程中學習鞏固對知識能有更深的記憶。網頁制作是一門很實用的學科,值得我們以后更深入的去學習。現(xiàn)在我掌握的制作知識還是太少,需要以后多與老師、同學們交流,自己在網絡上也需要更加深入的挖掘有關知識。

(二)問題與不足

對一些代碼的作用不了解,亂加運用導致頁面混亂,而且缺少獨自處理錯誤與難題的能力,對于有些知識僅是一看就過,其實自己根本沒有掌握,而且掌握了的也是一知半解,沒有將知識加以用工,總是想做些什么但是真到了做的時候不會,還得去翻書。

第三篇:網絡編程實驗報告

實驗一 TCP Socket API程序設計

一、預備知識

1.網絡編程基本概念

網絡上的計算機間的通訊,實質上是網絡中不同主機上的程序之間的通訊。在互聯(lián)網中使用IP地址來標識不同的主機,在網絡協(xié)議中使用端口號來標識主機上不同進程,即使用(IP地址,端口號)二元組。

套接字(Socket)用于描述IP地址和端口,是一個通信鏈的句柄,通信時一個網絡程序將要傳輸?shù)囊欢涡畔懭胨谥鳈C的Socket中,該Socket通過與網絡接口卡相連的傳輸介質將這段信息發(fā)送到另一臺主機的Socket中,以供其他程序使用。

圖1-1 TCP通信流程 2.TCP通信流程

TCP程序是面向連接的,程序運行后,服務器一直處于監(jiān)聽狀態(tài),客戶端與服務器通信之前必須首先發(fā)起連接請求,由服務器接收請求并在雙方之間建立連接后才可以互相通信。

二、實驗目的

1.了解Winsock API編程原理; 2.掌握TCP Socket程序的編寫; 3.了解C/S模式的特點; 4.學會解決實驗中遇到的問題。

三、實驗任務

使用Winsock API相關類實現(xiàn)TCP Socket通信程序,并能成功運行。

四、實驗環(huán)境及工具

1.Windows2000/XP/7 2.Visual C++開發(fā)平臺 3.Visual Studio2010

五、實驗內容和步驟

參照《Visual C++網絡編程教程》書中81頁,TCP Socket API程序設計。連接:

void CChatClientDlg::OnConnect(){

WSADATA wsd;

//WSADATA結構

WSAStartup(MAKEWORD(2,2),&wsd);

//加載協(xié)議,使用Winsock 2.2版

m_client = socket(AF_INET,SOCK_STREAM,0);//創(chuàng)建流式套接字

//服務器地址

sockaddr_in serveraddr;

UpdateData();

if(ServerIP.IsBlank())

{

AfxMessageBox(“請指定服務器IP!”);

return;

}

if(sPort.IsEmpty())

{

AfxMessageBox(“請指定端口!”);

return;

}

//獲取服務器進程的IP和端口

BYTE nFild[4];

CString sIP;

ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);

sIP.Format(“%d.%d.%d.%d”,nFild[0],nFild[1],nFild[2],nFild[3]);

//設置服務器地址結構的內容

serveraddr.sin_family = AF_INET;

serveraddr.sin_addr.S_un.S_addr = inet_addr(sIP);

serveraddr.sin_port = htons(atoi(sPort));

//發(fā)起連接須指明要訪問的服務器進程地址,這個地址存儲在serveraddr中

if(connect(m_client,(sockaddr*)&serveraddr,sizeof(serveraddr))!= 0)

{

MessageBox(“連接失敗”);

return;

}

else

{

m_ListWords.AddString(“連接服務器成功!”);

m_ListWords.SetTopIndex(m_ListWords.GetCount()1);

ServerIP.EnableWindow();

ServerPort.EnableWindow();

m_ButtonConnect.EnableWindow();

m_ButtonDisconnect.EnableWindow(false);

m_EditWords.EnableWindow(false);

m_ButtonSend.EnableWindow(false);

m_ButtonExit.EnableWindow();}

“發(fā)送”按鈕事件過程代碼如下:

void CChatClientDlg::OnSend(){

//向服務器發(fā)送信息

UpdateData();

if(m_sWords.IsEmpty())

{

AfxMessageBox(“發(fā)送的消息不能為空!”);

return;

}

//開始發(fā)送數(shù)據

int i = send(m_client,m_sWords.GetBuffer(0),m_sWords.GetLength(),0);

m_ListWords.AddString(“發(fā)送:” + m_sWords);

m_ListWords.SetTopIndex(m_ListWords.GetCount()1);

closesocket(m_client);

ServerIP.EnableWindow();

ServerPort.EnableWindow();

m_ButtonConnect.EnableWindow();

m_ButtonDisconnect.EnableWindow(false);

m_EditWords.EnableWindow(false);

m_ButtonSend.EnableWindow(false);

m_ButtonExit.EnableWindow();} “清空”按鈕的事件過程: m_ListWords.ResetContent();“關于”按鈕的事件過程: CAboutDlg dlgAbout;dlgAbout.DoModal();

服務器端: 開始監(jiān)聽代碼:

void CChatServerDlg::OnListen(){

WSADATA wsd;

//WSADATA結構

WSAStartup(MAKEWORD(2,2),&wsd);

//加載協(xié)議棧,使用Winsock 2.2版

m_server = socket(AF_INET,SOCK_STREAM,0);//創(chuàng)建流式套接字

//將網絡中的事件關聯(lián)到窗口的消息函數(shù)中,定義消息號為20000,偵測客戶端的連接請求

WSAAsyncSelect(m_server,m_hWnd,20000,FD_ACCEPT);

m_client = 0;

BYTE nFild[4];

CString sIP;

UpdateData();

if(ServerIP.IsBlank())

{

AfxMessageBox(“請設置IP地址!”);

return;

}

if(sPort.IsEmpty())

{

AfxMessageBox(“請設置監(jiān)聽端口!”);

return;

}

ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);

sIP.Format(“%d.%d.%d.%d”,nFild[0],nFild[1],nFild[2],nFild[3]);

//服務器地址

sockaddr_in serveraddr;

serveraddr.sin_family = AF_INET;

serveraddr.sin_addr.S_un.S_addr = inet_addr(sIP);

serveraddr.sin_port = htons(atoi(sPort));

//綁定地址

if(bind(m_server,(sockaddr*)&serveraddr,sizeof(serveraddr)))

{

MessageBox(“綁定地址失敗.”);

return;

}

//監(jiān)聽開始,服務器等待連接請求的到來

listen(m_server,5);

m_ListWords.AddString(“監(jiān)聽開始:”);

m_ListWords.AddString(“地址” + sIP + “ 端口” + sPort);

m_ListWords.AddString(“等待客戶端連接??”);

//界面完善

m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);

ServerIP.EnableWindow(false);

ServerPort.EnableWindow(false);

m_ButtonListen.EnableWindow(false);

m_ButtonStopListen.EnableWindow();

m_ButtonClear.EnableWindow();

m_ButtonExit.EnableWindow(false);} “停止監(jiān)聽”按鈕事件過程代碼如下: void CChatServerDlg::OnStopListen(){

//停止監(jiān)聽

closesocket(m_server);

m_ListWords.AddString(“停止監(jiān)聽”);

m_ListWords.SetTopIndex(m_ListWords.GetCount()1);} “斷開”按鈕事件過程代碼如下: void CChatServerDlg::OnDisconnect(){

closesocket(m_client);

m_ListWords.AddString(“與客戶端斷開”);

m_ListWords.SetTopIndex(m_ListWords.GetCount()1);

//界面完善

m_ButtonDisconnect.EnableWindow();

m_EditWords.EnableWindow();

m_ButtonSend.EnableWindow();} ReceiveData()函數(shù)代碼如下:

void CChatServerDlg::ReceiveData(){

//接收客戶端的數(shù)據

char buffer[1024];

int num = recv(m_client,buffer,1024,0);

buffer[num] = 0;

CString sTemp;

sTemp.Format(“收到:%s”,buffer);

m_ListWords.AddString(sTemp);//顯示信息

m_ListWords.SetTopIndex(m_ListWords.GetCount()1);

closesocket(m_client);//關閉與客戶端通信的Socket

WSAAsyncSelect(m_server,m_hWnd,20000,FD_ACCEPT);//準備接收新的客戶端連接

//界面完善

m_ButtonDisconnect.EnableWindow(false);

m_EditWords.EnableWindow(false);

m_ButtonSend.EnableWindow(false);} 服務器的初始化代碼如下: //界面初始化

m_ButtonStopListen.EnableWindow(false);m_ButtonDisconnect.EnableWindow(false);m_ButtonClear.EnableWindow(false);m_EditWords.EnableWindow(false);m_ButtonSend.EnableWindow(false);

運行結果:

六、思考題

1.用Winsock API編程時,主要進行哪些通行的操作步驟? 2.闡述C/S模式的通信過程。答:

1.通行的操作

1.Winsock的打開(WSAStartup())。2.建立套接字(socket()或WSASocket())。3.地址綁定(bind())。

4.服務器監(jiān)聽連接(listen())。

5.客戶端提出連接申請(connect()或WSAConnect())。6.服務器接收客戶端的連接請求(accept()或WSAAccept())。7.數(shù)據的發(fā)送(send()或WSASend(),sendto()或WSASendTo())。8.數(shù)據的接收(recv()或WSARecv(),recvfrom()或WSARecvfrom())。9.關閉套接字(closesocket())。10.關閉Winsock(WSACleanup())。

2通信過程

第四篇:網絡編程實習作業(yè)

網絡編程實習作業(yè)

一. 實習內容:

? 了解插口(socket)實現(xiàn)原理。

? 在某一種平臺(Linux,Unix系列或Windows系列)下進行網絡客戶機-服務器編程。

二. 主要參考書目:

? W.Richard Stevens, “UNIX Network Programming Networking APIs: Scokets and XTI(Volume 1,Second Edition)”,清華大學出版社 Prentice-Hall International, Inc.或其中文版 “UNIX網絡編程(第1卷,第2版)” 經典讀物,目前的最新版是第三版

? Douglas Comer,《用TCP/IP進行網際互連 第3卷:客戶機-服務器編程和應用(第2版)》 或其英文版 Internetworking With TCP/IP Vol III: Client-Server Programming And Application(Second Edition)以下簡稱《客戶機-服務器編程》

三. 實習題目:

1:編寫DAYTIME服務的UDP客戶機和服務器的實現(xiàn)。

基本要求:

當服務器端收到客戶端的請求后,將當前daytime返回給客戶端,客戶端收到該回應后,將收到的daytime顯示到輸出中。

(其中在Linux或Unix環(huán)境中,當前daytime的獲得參考函數(shù)time()和ctime())

2:熟悉Http協(xié)議的請求和響應格式,編寫一個簡單的Http服務器。題目描述參考《自上而下計算機網絡》(第三版 作者James F.Kurose)第二章課后編程作業(yè)1。

基本要求:正確解析Http請求,實現(xiàn)簡單的GET請求回應。模擬一個對象(如:文件index.html)的GET回應(如:回應一個字符串),對于其他的對象,則根據Http響應格式回應對象不存在信息。3 通過瀏覽器可檢測自己的程序。如:輸入,查看其響應結果。對http請求的處理必須采用多進程實現(xiàn),即主進程負責等待請求連接,每當收到一個請求后,產生一個子進程對該請求做單獨處理,主進程繼續(xù)等待新請求,子進程在處理完其請求后結束自己。詳細要求參考課本要求。(多進程編程參考函數(shù)fork())

要求:

源程序部分帶有必要的注釋,備有一份文檔說明各個程序中的思路和關鍵技術。注意,只能使用C語言編寫。可以是windows或者linux下可執(zhí)行,二種環(huán)境選擇一種即可。

評分標準

90% 以上 :在程序說明文檔中,可以體現(xiàn)出自己對本程序所用到的技術有較深刻的理解。

程序有較好的可讀性(關鍵部分的注釋比較詳細)。

80% :符合要求,程序說明的比較詳細,思路比較清楚。

70% :只有程序沒有說明文檔的,70%-60% :缺少說明文檔

60% 以下 :程序或說明文檔完全和別人的一樣(抄襲于被抄襲者一樣處理)。

注:作業(yè)包括程序部分(.c,.cpp,.h等源碼和.exe等可執(zhí)行文件,不要.obj 等其他文件)和程序說明文檔,文件大小最好不要超過1M。程序說明要體現(xiàn)出你所用到的關鍵技術,要說清楚自己定義函數(shù)的功能及實現(xiàn),要有關鍵部分的流程圖。要按時交作業(yè),晚交的要相應的扣分。請將程序打成一個包,包名統(tǒng)一采用“學號_姓名”形式,然后發(fā)到

network_tju@163.com

郵件的Title也是“學號_姓名”

請一定將學號放在前面

5截至日期:2009年4月20日

(注:1.以郵箱接收到的時間戳為準。2.在提交作業(yè)時,請最好選擇發(fā)送并保存郵件,避免由于投遞失敗而導致作業(yè)無法按時完成。(就是避免死無對證)3.杜絕抄襲,請盡早開始著手這項作業(yè))

第五篇:網絡編程實習報告

[實習目的]

通過理論聯(lián)系實際,鞏固所學的知識,提高處理實際問題的能力,并為自己能順利與社會環(huán)境接軌做準備。[實習任務]Linux下網絡服務器開發(fā)(基于C語言);本文總結了我對Linux下網絡服務器模型的認識。[實習內容]一.循環(huán)服務器1.循環(huán)服務器在同一個時刻只可以響應一個客戶端的請求,對多個客戶程序的處理是采用循環(huán)的方式進行; 2.UDp循環(huán)服務器的實現(xiàn)非常簡單:UDp服務器每次從套接字上讀取一個客戶端的請求,處理, 然后將結果返回給客戶機;2.1.算法如下(UDp服務器): socket(...);

bind(...);

while(1)

{

recvfrom(...);

process(...);

sendto(...);

}3.TCp循環(huán)服務器的實現(xiàn)也不難:TCp服務器接受一個客戶端的連接,然后處理,完成了這個客戶的所有請求后,斷開連接;3.1.算法如下(TCp服務器):

socket(...);

bind(...);

listen(...);

while(1)

{

accept(...);

while(1)

{

read(...);

process(...);write(...);

}

close(...);

}3.2.TCp循環(huán)服務器一次只能處理一個客戶端的請求.只有在這個客戶的所有請求都滿足后, 服務器才可以繼續(xù)后面的請求.這樣如果有一個客戶端占住服務器不放時,其它的客戶機都不能工作了.因此,TCp服務器一般很少用循環(huán)服務器模型的.二.并發(fā)服務器1.為了彌補循環(huán)TCp服務器的缺陷,人們又想出了并發(fā)服務器的模型。并發(fā)服務器的思想是每一個客戶機的請求并不由服務器直接處理,而是服務器創(chuàng)建一個子進程來處理;2.使用并發(fā)服務器可以使服務器進程在同一個時刻有多個子進程和不同的客戶程序連接、通信;在客戶程序看來,服務器可以同時并發(fā)地處理多個客戶的請求;3.算法如下(TCp服務器):socket(...);

bind(...);

listen(...);

while(1)

{

accept(...);

if(fork(..)==0)

{

close(...);while(1)

{

read(...);

process(...);

write(...);

}

close(...);

exit(...);

}

close(...);

}4.TCp并發(fā)服務器可以解決TCp循環(huán)服務器客戶機獨占服務器的情況,改善了對客戶程序的響應速度;不過也同時帶來了一個不小的問題:為了響應客戶機的請求,服務器要創(chuàng)建子進程來處理,而創(chuàng)建子進程是一種非常消耗資源的操作,這明顯增加了系統(tǒng)調度的開銷;5.為了解決創(chuàng)建子進程帶來的系統(tǒng)資源消耗,人們又想出了多路復用I/O模型.5.1.該模型一般用函數(shù)select和相關的四個宏定義:intselect(intfd,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,structtimeval*timeout)

voidFD_SET(intfd,fd_set*fdset)

voidFD_CLR(intfd,fd_set*fdset)

voidFD_ZERO(fd_set*fdset)

intFD_ISSET(intfd,fd_set*fdset)5.2.一般的來說當我們在向文件讀寫時,進程有可能在讀寫時候阻塞,直到一定的條件滿足.比如我們從一個套接字讀數(shù)據時,可能緩沖區(qū)里面沒有數(shù)據可讀(通信的對方還沒有發(fā)送數(shù)據過來),這個時候我們的讀調用就會等待(阻塞)直到有數(shù)據可讀.如果我們不希望阻塞,我們的一個選擇是把socket設置為非阻塞模式來實現(xiàn);int socketfd;socketfd=socket(AF_INET,SOCK_STREAM,0);fcntl(socketfd,F_SETFL,O_NONBLOCK);通過設置socket為非阻塞模式,可以實現(xiàn)“輪循”多個socket,當企圖從一個沒有數(shù)據等待處理的非阻塞socket讀取數(shù)據時,函數(shù)立即返回,但是這種“輪循”會使CpU處于忙等待方式,降低了性能,select函數(shù)解決了這個問題;5.3.在我們調用select時進程會一直阻塞直到以下的一種情況發(fā)生.1)有文件可以讀.2)有文件可以寫.3)超時所設置的時間到;5.4.算法如下(多路復用I/O模型):初始化(socket,bind,listen);

while(1)

{ 設置監(jiān)聽讀寫文件描述符(FD_*);

調用select;

如果是傾聽套接字就緒,說明一個新的連接請求建立

建立連接(accept);

加入到監(jiān)聽文件描述符中去;

否則說明是一個已經連接過的描述符

進行操作(read或者write);}

多路復用I/O可以解決資源限制的問題.著模型實際上是將UDp循環(huán)模型用在了TCp上面.這也就帶來了一些問題.如由于服務器依次處理客戶的請求,所以可能會導致有的客戶會等待很久。三.I/O模型1.網絡服務器模型根據I/O模型的不同實現(xiàn)而來的;2.I/O模型分為同步I/O和異步I/O;同步I/O又包括阻塞I/O、非阻塞I/O、信號驅動I/O、多路復用I/O;可根據不同的要求利用不同的I/O模型實現(xiàn)不同是網絡服務器。[實習心得] 通過近幾個月的實習,基本上掌握了Linux下C語言網絡編程的一些算法和技巧,提高了自己的能力。專業(yè):計算機網絡技術 班級:03631 學號:63103089 姓名:呂亮亮——XX.05.23

下載網絡編程常見問題總結word格式文檔
下載網絡編程常見問題總結.doc
將本文檔下載到自己電腦,方便修改和收藏,請勿使用迅雷等下載。
點此處下載文檔

文檔為doc格式


聲明:本文內容由互聯(lián)網用戶自發(fā)貢獻自行上傳,本網站不擁有所有權,未作人工編輯處理,也不承擔相關法律責任。如果您發(fā)現(xiàn)有涉嫌版權的內容,歡迎發(fā)送郵件至:645879355@qq.com 進行舉報,并提供相關證據,工作人員會在5個工作日內聯(lián)系你,一經查實,本站將立刻刪除涉嫌侵權內容。

相關范文推薦

    網絡編程實習報告

    廣東應屆生實習報告網在線編輯整理本文。[實習目的] 通過理論聯(lián)系實際,鞏固所學的知識,提高處理實際問題的能力,并為自己能順利與社會環(huán)境接軌做準備。[實習任務]Linux下網絡服......

    java網絡編程考試總結要點(推薦五篇)

    1、動靜態(tài)網頁的概念,常見后綴及基本區(qū)別。 靜態(tài)網頁:是指用HTML標記語言等來編排,頁面中的內容固定不變,存盤后一般以*.html、*.htm等文件形式存在的網頁。 動態(tài)網頁:是指網頁中......

    嵌入式串口和網絡編程實驗報告

    嵌入式實驗報告 題目:linux串口和網絡編程 一、實驗目的: 1、強化本學期所學的相關的內容。 2、掌握串口相關設置。 3、強化基于TCP網絡傳輸?shù)娜挝帐帧? 4、自學Linux......

    《網絡高級編程》實驗報告要求

    一、 實驗報告為紙質報告,手寫,不少于8頁紙。 二、 報告首頁為標準實驗報告封面,有課程名稱、實驗名稱、 姓名、時間 三、 報告內容為: 1、 2、 3、 4、 實驗目的 實驗題目 實驗......

    網絡發(fā)票常見問題解決方法

    網絡發(fā)票常見問題解決方法如下: 1. 電子發(fā)票的登錄密碼忘記了怎么辦? 財務負責人和代理開票人的密碼忘記了,可以通過system用戶進行修改,system用戶和納稅申報登錄密碼忘記了,需......

    刀具和編程總結

    ① 白鋼刀(即高速鋼刀具)因其通體銀白色而得名,主要用于直壁加工。白鋼刀價格便宜,但切削壽命短、吃刀量小、進給速度低、加工效率低,在數(shù)控加工中較少使用。 ② 飛刀(即鑲嵌式刀......

    編程題總結(范文大全)

    C作業(yè)匯總 1. short a,b=32767; /*short類型在內存中占2B*/ a=b+1; 問:a的值是多少?并分析原因。 2. 有一4位數(shù)整數(shù),假設用abcd表示,請把這個4位數(shù)的每個數(shù)位用表達式表示出來......

    數(shù)據庫編程總結(推薦)

    數(shù)據庫編程總結 當前各種主流數(shù)據庫有很多,包括Oracle, MS SQL Server, Sybase, Informix, MySQL, DB2, Interbase / Firebird, PostgreSQL, SQLite, SAP/DB, TimesTen, MS A......

主站蜘蛛池模板: 欧美激情性做爰免费视频| 欧美黑人巨大xxxxx| 怡红院精品久久久久久久高清| 国产免费人成视频在线播放播| 欧美日韩亚洲国产欧美电影| 狠狠cao日日穞夜夜穞av| 看曰本女人大战黑人视频| 欧美熟妇与小伙性欧美交| 欧美国产亚洲日韩在线二区| 欧美人与动牲交a欧美精品| 欧美另类高清zo欧美| 亚洲 暴爽 av人人爽日日碰| 东京热人妻中文无码| 国产国拍亚洲精品mv在线观看| 97人妻人人揉人人躁人人| 无码一区二区波多野结衣播放搜索| 亚洲日韩中文无码久久| 黑人上司粗大拔不出来电影| 嫖妓丰满肥熟妇在线精品| 国产成人精品一区二区在线小狼| 黑人巨大精品欧美一区二区| 日韩一区二区三区无码免费视频| 亚洲中文字幕无码久久2018| 成人无码一区二区三区网站| 精品国产第一国产综合精品| 美女视频黄的全免费的| 隔壁人妻偷人bd中字| 久久久久亚洲精品天堂| 国产精品久线在线观看| 熟妇女人妻丰满少妇中文字幕| 精品无码人妻一区二区三区不卡| 男人添女人下部高潮视频| 鲁大师影院在线观看| 99尹人香蕉国产免费天天| 久久久久久久无码高潮| 综合天堂av久久久久久久| 国产麻豆亚洲精品一区二区| 无码中文字幕乱码一区| 欧美精品一国产成人综合久久| 国产亚洲视频在线观看网址| 亚洲欧美在线观看|