常見的網絡編程面試題

原文鏈接:https://blog.csdn.net/weiyuefei/article/details/50413543

http://www.360doc.com/content/14/0724/21/1073512_396828405.shtml


轉載鏈接 :https://blog.csdn.net/weiyuefei/article/details/50413543

1:tcp和udp的區別

TCP:是面向連接的流傳輸控制協議,具有高可靠性,確保傳輸數據的正確性,有驗證重發機制,因此不會出現丟失或亂序。

UDP:是無連接的數據報服務,不對數據報進行檢查與修改,無須等待對方的應答,會出現分組丟失、重複、亂序,但具有較好的實時性,UDP段結構比TCP的段結構簡單,因此網絡開銷也小。

2:流量控制和擁塞控制

擁塞控制
網絡擁塞現象是指到達通信子網中某一部分的分組數量過多,使得該部分網絡來不及處理,以致引起這部分乃至整個網絡性能下降的現象,嚴重時甚至會導致網絡通信業務陷入停頓,即出現死鎖現象。擁塞控制是處理網絡擁塞現象的一種機制。
流量控制
數據的傳送與接收過程當中很可能出現收方來不及接收的情況,這時就需要對發方進行控制,以免數據丟失。

3:多線程如何同步

windows

線程同步有四種方式:臨界區、內核對象、互斥量、信號量

Linux

線程同步有最常用的是:互斥鎖、條件變量和信號量。

4:進程間通訊的方式有哪些,各有什麼優缺點

進程間通信

Linux 進程間通信(IPC)以下以幾部分發展而來:
早期UNIX進程間通信、基於System V進程間通信、基於Socket進程間通信和POSIX進程間通信。
UNIX進程間通信方式包括:管道、FIFO、信號。
System V進程間通信方式包括:System V消息隊列、System V信號燈、System V共享內存、
POSIX進程間通信包括:posix消息隊列、posix信號燈、posix共享內存。
現在linux使用的進程間通信方式:
(1)管道(pipe)和有名管道(FIFO)
(2)信號(signal)
(3)消息隊列
(4)共享內存
(5)信號量
(6)套接字(socket)

5:tcp連接建立的時候3次握手,斷開連接的4次握手的具體過程

建立連接採用的3次握手協議,具體是指:
第一次握手是客戶端connect連接到server,server accept client的請求之後,向client端發送一個消息,相當於說我都準備好了,你連接上我了,這是第二次握手,第3次握手就是client向server發送的,就是對第二次握手消息的確認。之後client和server就開始通訊了。
斷開連接的4次握手,具體如下:
斷開連接的一端發送close請求是第一次握手,另外一端接收到斷開連接的請求之後需要對close進行確認,發送一個消息,這是第二次握手,發送了確認消息之後還要向對端發送close消息,要關閉對對端的連接,這是第3次握手,而在最初發送斷開連接的一端接收到消息之後,進入到一個很重要的狀態time_wait狀態,這個狀態也是面試官經常問道的問題,最後一次握手是最初發送斷開連接的一端接收到消息之後。對消息的確認。

6:epoll與select的區別

select在一個進程中打開的最大fd是有限制的,由FD_SETSIZE設置,默認值是2048。不過 epoll則沒有這個限制,它所支持的fd上限是最大可以打開文件的數目,這個數字一般遠大於2048,一般來說內存越大,fd上限越大,1G內存都能達到大約10w左右。

select的輪詢機制是系統會去查找每個fd是否數據已準備好,當fd很多的時候,效率當然就直線下降了,epoll採用基於事件的通知方式,一旦某個fd數據就緒時,內核會採用類似callback的回調機制,迅速激活這個文件描述符,而不需要不斷的去輪詢查找就緒的描述符,這就是epoll高效最本質的原因。

無論是select還是epoll都需要內核把FD消息通知給用戶空間,如何避免不必要的內存拷貝就很重要,在這點上,epoll是通過內核於用戶空間mmap同一塊內存實現的,而select則做了不必要的拷貝

7:epoll中et和lt的區別與實現原理

LT:水平觸發,效率會低於ET觸發,尤其在大併發,大流量的情況下。但是LT對代碼編寫要求比較低,不容易出現問題。LT模式服務編寫上的表現是:只要有數據沒有被獲取,內核就不斷通知你,因此不用擔心事件丟失的情況。
ET:邊緣觸發,效率非常高,在併發,大流量的情況下,會比LT少很多epoll的系統調用,因此效率高。但是對編程要求高,需要細緻的處理每個請求,否則容易發生丟失事件的情況。


=======================================================================

1、connect方法會阻塞,請問有什麼方法可以避免其長時間阻塞?
答:最通常的方法最有效的是加定時器;也可以採用非阻塞模式。

2、網絡中,如果客戶端突然掉線或者重啓,服務器端怎麼樣才能立刻知道?
答:若客戶端掉線或者重新啓動,服務器端會收到復位信號,每一種tcp/ip得實現不一樣,控制機制也不一樣。

3.在子網210.27.48.21/30種有多少個可用地址?分別是什麼?
答:

簡:
30表示的是網絡號(network number)是30位,剩下2位中11是廣播(broadcast)地址,00是multicast地址,只有01和10可以作爲host address。

詳:
210.27.48.21/30代表的子網的網絡號是30位,即網絡號是210.27.48.21 & 255.255.255.251=210.27.48.20,此子網的地址空間是2位,即可以有4個地址:210.27.48.20, 210.27.48.21, 210.27.48.22, 210.27.48.23。第一個地址的主機號(host number/id)是0,而主機號0代表的是multicast地址。最後一個地址的最後兩位是11,主機號每一位都爲1代表的是廣播(broadcast)地址。所以只有中間兩個地址可以給host使用。其實那個問題本身不準確,廣播或multicast地止也是可以使用的地址,所以回答4也應該正確,當然問的人也可能是想要你回答2。我個人覺得最好的回答是一個廣播地址,一個multicast地址,2個unicast地址。

4.TTL是什麼?有什麼用處,通常那些工具會用到它?(ping? traceroute? ifconfig? netstat?)
答:
簡:TTL是Time To Live,一般是hup count,每經過一個路由就會被減去一,如果它變成0,包會被丟掉。它的主要目的是防止包在有迴路的網絡上死轉,浪費網絡資源。ping和traceroute用到它。

詳:TTL是Time To Live,目前是hup count,當包每經過一個路由器它就會被減去一,如果它變成0,路由器就會把包丟掉。IP網絡往往帶有環(loop),比如子網A和子網B有兩個路由器相連,它就是一個loop。TTL的主要目的是防止包在有迴路的網絡上死轉,因爲包的TTL最終後變成0而使得此包從網上消失(此時往往路由器會送一個ICMP包回來,traceroute就是根據這個做的)。ping會送包出去,所以裏面有它,但是ping不一定非要不可它。traceroute則是完全因爲有它才能成的。ifconfig是用來配置網卡的,netstat -rn 是用來列路由表的,所以都用不着它

5.路由表示做什麼用的?在linux環境中怎麼來配置一條默認路由?
答:
簡:路由表是用來決定如何將包從一個子網傳送到另一個子網的,換局話說就是用來決定從一個網卡接收到的包應該送的哪一張網卡上的。在Linux上可以用“route add default gw <默認路由器IP>”來配置一條默認路由。

詳:路由表是用來決定如何將包從一個子網傳送到另一個子網的,換局話說就是用來決定從一個網卡接收到的包應該送的哪一張網卡上的。路由表的每一行至少有目標網絡號、netmask、到這個子網應該使用的網卡。當路由器從一個網卡接收到一個包時,它掃描路由表的每一行,用裏面的netmask和包裏的目標IP地址做並邏輯運算(&)找出目標網絡號,如果此網絡號和這一行裏的網絡號相同就將這條路由保留下來做爲備用路由,如果已經有備用路由了就在這兩條路由裏將網絡號最長的留下來,另一條丟掉,如此接着掃描下一行直到結束。如果掃描結束任沒有找到任何路由,就用默認路由。確定路由後,直接將包送到對應的網卡上去。在具體的實現中,路由表可能包含更多的信息爲選路由算法的細節所用。題外話:路由算法其實效率很差,而且不scalable,解決辦法是使用IP交換機,比如MPLS。
在Linux上可以用“route add default gw <默認路由器IP>”來配置一條默認路由。

6.在網絡中有兩臺主機A和B,並通過路由器和其他交換設備連接起來,已經確認物理連接正確無誤,怎麼來測試這兩臺機器是否連通?如果不通,怎麼來判斷故障點?怎麼排除故障?
答:測試這兩臺機器是否連通:從一臺機器ping另一臺機器
     如果ping不通,用traceroute可以確定是哪個路由器不能連通,然後再找問題是在交換設備/hup/cable等。

7.網絡編程中設計併發服務器,使用多進程 與 多線程 ,請問有什麼區別? 
答案一:
1,進程:子進程是父進程的複製品。子進程獲得父進程數據空間、堆和棧的複製品。
2,線程:相對與進程而言,線程是一個更加接近與執行體的概念,它可以與同進程的其他線程共享數據,但擁有自己的棧空間,擁有獨立的執行序列。
兩者都可以提高程序的併發度,提高程序運行效率和響應時間。
線程和進程在使用上各有優缺點:線程執行開銷小,但不利於資源管理和保護;而進程正相反。同時,線程適合於在SMP機器上運行,而進程則可以跨機器遷移。

答案二:
根本區別就一點:用多進程每個進程有自己的地址空間(address space),線程則共享地址空間。所有其它區別都是由此而來的:
1。速度:線程產生的速度快,線程間的通訊快、切換快等,因爲他們在同一個地址空間內。
2。資源利用率:線程的資源利用率比較好也是因爲他們在同一個地址空間內。
3。同步問題:線程使用公共變量/內存時需要使用同步機制還是因爲他們在同一個地址空間內。
等等


3. 網絡編程的一般步驟

對於TCP連接:

1.服務器端1)創建套接字create;2)綁定端口號bind;3)監聽連接listen;4)接受連接請求accept,並返回新的套接字;5)用新返回的套接字recv/send;6)關閉套接字。

2.客戶端1)創建套接字create; 2)發起建立連接請求connect; 3)發送/接收數據send/recv;4)關閉套接字。

TCP總結:

Server端:create -- bind -- listen--  accept--  recv/send-- close

Client端:create------- conncet------send/recv------close.


對於UDP連接:

1.服務器端:1)創建套接字create;2)綁定端口號bind;3)接收/發送消息recvfrom/sendto;4)關閉套接字。

2.客戶端:1)創建套接字create;2)發送/接收消息sendto/recvfrom;3)關閉套接字.

UDP總結:

Server端:create----bind ----recvfrom/sendto----close

Client端:create----  sendto/recvfrom----close.


5. TCP的重發機制是怎麼實現的?

       1.滑動窗口機制,確立收發的邊界,能讓發送方知道已經發送了多少(已確認)、尚未確認的字節數、尚待發送的字節數;讓接收方知道(已經確認收到的字節數)。

       2.選擇重傳,用於對傳輸出錯的序列進行重傳。

6. TCPUDP的區別?

       1)TCP面向連接(三次握手機制),通信前需要先建立連接;UDP面向無連接,通信前不需要建立連接;

       2)TCP保障可靠傳輸(按序、無差錯、不丟失、不重複);UDP不保障可靠傳輸,使用最大努力交付;

       3)TCP面向字節流的傳輸,UDP面向數據報的傳輸。

   TCP---傳輸控制協議,提供的是面向連接、可靠的字節流服務。當客戶和服務器彼此交換數據前,必須先在雙方之間建立一個TCP連接,之後才能傳輸數據。TCP提供超時重發,丟棄重複數據,檢驗數據,流量控制等功能,保證數據能從一端傳到另一端。
UDP---用戶數據報協議,是一個簡單的面向數據報的運輸層協議。UDP不提供可靠性,它只是把應用程序傳給IP層的數據報發送出去,但是並不能保證它們能到達目的地。由於UDP在傳輸數據報前不用在客戶和服務器之間建立一個連接,且沒有超時重發等機制,故而傳輸速度很快


8.TCP爲什麼不是兩次連接?而是三次握手?

如果AB兩個進程通信,如果僅是兩次連接。可能出現的一種情況就是:A發送完請報文以後,由於網絡情況不好,出現了網絡擁塞,即B延時很長時間後收到報文,即此時A將此報文認定爲失效的報文。B收到報文後,會向A發起連接。此時兩次握手完畢,B會認爲已經建立了連接可以通信,B會一直等到A發送的連接請求,而A對失效的報文回覆自然不會處理。依次會陷入B忙等的僵局,造成資源的浪費。

9. connect方法會阻塞,請問有什麼方法可以避免其長時間阻塞?

可以考慮採用異步傳輸機制,同步傳輸與異步傳輸的主要區別在於同步傳輸中,如果調用recvfrom後會一致阻塞運行,從而導致調用線程暫停運行;異步傳輸機制則不然,會立即返回。


8.網絡編程中設計併發服務器,使用多進程多線程,請問有什麼區別?

答案一:

1,進程:子進程是父進程的複製品。子進程獲得父進程數據空間、堆和棧的複製品。

2,線程:相對與進程而言,線程是一個更加接近與執行體的概念,它可以與同進程的其他線程共享數據,但擁有自己的棧空間,擁有獨立的執行序列。兩者都可以提高程序的併發度,提高程序運行效率和響應時間。

線程和進程在使用上各有優缺點:線程執行開銷小,但不利於資源管理和保護;而進程正相反。同時,線程適合於在SMP機器上運行,而進程則可以跨機器遷移。

答案二:

根本區別就一點:用多進程每個進程有自己的地址空間(address space),線程則共享地址空間。所有其它區別都是由此而來的:

1。速度:線程產生的速度快,線程間的通訊快、切換快等,因爲他們在同一個地址空間內。

2。資源利用率:線程的資源利用率比較好也是因爲他們在同一個地址空間內。

3。同步問題:線程使用公共變量/內存時需要使用同步機制還是因爲他們在同一個地址空間內。

等等


17.流量控制和擁塞控制的實現機制

擁塞控制
網絡擁塞現象是指到達通信子網中某一部分的分組數量過多,使得該部分網絡來不及處理,以致引起這部分乃至整個網絡性能下降的現象,嚴重時甚至會導致網絡通信業務陷入停頓,即出現死鎖現象。擁塞控制是處理網絡擁塞現象的一種機制。
流量控制
數據的傳送與接收過程當中很可能出現收方來不及接收的情況,這時就需要對發方進行控制,以免數據丟失。

流量控制機制:

  流量控制用於防止在端口阻塞的情況下丟幀,這種方法是當發送或接收緩衝區開始溢出時通過將阻塞信號發送回源地址實現的。流量控制可以有效的防止由於網絡中瞬間的大量數據對網絡帶來的衝擊,保證用戶網絡高效而穩定的運行。

18.多線程如何同步:

 在這裏簡單說一下linux多線程同步的方法吧(win上有一定的差別,也有一定的累似)

1:線程數據,每個線程數據創建一個鍵,它和這個鍵相關聯,在各個線程裏,都使用這個鍵來指代線程數據,但在不同的線程裏,這個鍵代表的數據是不同的,在同一個線程裏,它代表同樣的數據內容。以此來達到線程安全的目的。
2:互斥鎖,就是在各個線程要使用的一些公共數據之前加鎖,使用之後釋放鎖,這個是非常常用的線程安全控制的方法,而頻繁的加解鎖也對效率有一定的影響。
3:條件變量,而條件變量通過允許線程阻塞和等待另一個線程發送信號的方法彌補了互斥鎖的不足,它常和互斥鎖一起使用。使用時,條件變量被用來阻塞一個線程,當條件不滿足時,線程往往解開相應的互斥鎖並等待條件發生變化。一旦其它的某個線程改變了條件變量,它將通知相應的條件變量喚醒一個或多個正被此條件變量阻塞的線程。這些線程將重新鎖定互斥鎖並重新測試條件是否滿足。一般說來,條件變量被用來進行線程間的同步。
4:信號量,信號量本質上是一個非負的整數計數器,它被用來控制對公共資源的訪問。當公共資源增加時,調用函數sem_post()增加信號量。只有當信號量值大於0時,才能使用公共資源,使用後,函數sem_wait()減少信號量。函數sem_trywait()和函數pthread_ mutex_trylock()起同樣的作用,它是函數sem_wait()的非阻塞版本
另外pthread_join也可以等待一個線程的終止。

19.進程間通訊的方式有哪些,各有什麼優缺點

進程間通信主要包括管道, 系統IPC(包括消息隊列,信號量,共享存儲), socket.

管道包括三種:1)普通管道PIPE, 通常有種限制,一是半雙工,只能單向傳輸;二是只能在父子進程間使用. 2)流管道s_pipe: 去除了第一種限制,可以雙向傳輸. 3)命名管道:name_pipe, 去除了第二種限制,可以在許多並不相關的進程之間進行通訊.

系統IPC的三種方式類同,都是使用了內核裏的標識符來識別

管道: 優點是所有的UNIX實現都支持, 並且在最後一個訪問管道的進程終止後,管道就被完全刪除;缺陷是管道只允許單向傳輸或者用於父子進程之間

系統IPC: 優點是功能強大,能在毫不相關進程之間進行通訊; 缺陷是關鍵字KEY_T使用了內核標識,佔用了內核資源,而且只能被顯式刪除,而且不能使用SOCKET的一些機制,例如select,epoll等.

socket可以跨網絡通訊,其他進程間通訊的方式都不可以,只能是本機進程通訊。


20.tcp連接建立的時候3次握手的具體過程,以及其中的每一步是爲什麼

建立連接採用的3次握手協議,具體是指:

第一次握手是客戶端connect連接到server,server accept client的請求之後,向client端發送一個消息,相當於說我都準備好了,你連接上我了,這是第二次握手,第3次握手就是client向server發送的,就是對第二次握手消息的確認。之後client和server就開始通訊了。


21.tcp斷開連接的具體過程,其中每一步是爲什麼那麼做

斷開連接的4次握手,具體如下:

斷開連接的一端發送close請求是第一次握手,另外一端接收到斷開連接的請求之後需要對close進行確認,發送一個消息,這是第二次握手,發送了確認消息之後還要向對端發送close消息,要關閉對對端的連接,這是第3次握手,而在最初發送斷開連接的一端接收到消息之後,進入到一個很重要的狀態time_wait狀態,這個狀態也是面試官經常問道的問題,最後一次握手是最初發送斷開連接的一端接收到消息之後。對消息的確認。



=======================

1.C++模板的作用。 
將算法與具體對象分離,與類型無關,通用,節省精力

2.socket編程,如果client斷電了,服務器如何快速知道???
有以下幾個技術:
使用定時器(適合有數據流動的情況); 使用socket選項SO_KEEPALIVE(適合沒有數據流動的情況); 
 

3.fork()一子進程程後 父進程癿全局變量能不能使用???
fork後子進程將會擁有父進程的幾乎一切資源,父子進程的都各自有自己的全局變量。不能通用,不同於線程。對於線程,各個線程共享全局變量。

4.4G的long型整數中找到一個最大的,如何做????
我的想法是要找到最大的肯定要遍歷所有的數的,而且不能將數據全部讀入內存,可能不足。算法的時間複雜度肯定是O(n)
感覺就是遍歷,比較。。。。還能怎麼改進呢????
可以改進的地方,就是讀入內存的時候,一次多讀些。。。。
需 要注意的就是每次從磁盤上儘量多讀一些數到內存區,然後處理完之後再讀入一批。減少IO次數,自然能夠提高效率。而對於類快速排序方法,稍微要麻煩一些: 分批讀入,假設是M個數,然後從這M個數中選出n個最大的數緩存起來,直到所有的N個數都分批處理完之後,再將各批次緩存的n個數合併起來再進行一次類快 速排序得到最終的n個最大的數就可以了。在運行過程中,如果緩存數太多,可以不斷地將多個緩存合併,保留這些緩存中最大的n個數即可。由於類快速排序的時 間複雜度是O(N),這樣分批處理再合併的辦法,依然有極大的可能會比堆和敗者樹更優。當然,在空間上會佔用較多的內存。 

此題還有個變種,就是尋找K個最大或者最小的數。有以下幾種算法:
容量爲K的最大堆/最小堆,假設K可以裝入內存;
如果N個數可以裝入內存,且都小於MAX,那麼可以開闢一個MAX大的數組,類似計數排序。。。從數組尾部掃描K個最大的數,頭部掃描K個最小的數。
 

5.有千萬個string在內存怎麼高速查找,插入和刪除???
對千萬個string做hash,可以實現高速查找,找到了,插入和刪除就很方便了。
關鍵是如何做hash,對string做hash,要減少碰撞頻率。
In the String class, for example, the hash code h of a string s of length n is calculated as
\( \texttt{h} \;=\; \texttt{s[0]}*31^{n-1} + \texttt{s[1]}*31^{n-2} + \cdots + \texttt{s[n-1]} \)
or, in code,
int h = 0; for (int i = 0; i < n; i++) {     h = 31*h + s.charAt(i); }
In general the arithmetic operations in such expressions will use 32-bit modular arithmetic ignoring overflow
在實際中,BKDRhash函數比較好
// BKDR Hash unsigned int BKDRHash(char *str) { unsigned int seed = 131; // 31 131 1313 13131 131313 etc.. unsigned inthash = 0;   while (*str) { hash = hash * seed + (*str++); }   return (hash & 0x7FFFFFFF); }

6.tcp三次握手的過程,accept發生在三次握手哪個階段?
三次握手:C----->SYN K
              S------>ACK K+1 SYN J
              C------->ACK J+1   
              DONE!
client 的 connect  引起3次握手
server 在socket, bind, listen後,阻塞在accept,三次握手完成後,accept返回一個fd,
因此accept發生在三次握手之後。。。。。。
7.Tcp流, udp的數據報,之間有什麼區別,爲什麼TCP要叫做數據流?
TCP本身是面向連接的協議,S和C之間要使用TCP,必須先建立連接,數據就在該連接上流動,可以是雙向的,沒有邊界。所以叫數據流 ,佔系統資源多
UDP不是面向連接的,不存在建立連接,釋放連接,每個數據包都是獨立的包,有邊界,一般不會合並。
TCP保證數據正確性,UDP可能丟包,TCP保證數據順序,UDP不保證
8.
const的含義及實現機制,比如:const int i,是怎麼做到i只可讀的?
const指示對象爲常量,只讀。
實現機制:這些在編譯期間完成,對於內置類型,如int, 編譯器可能使用常數直接替換掉對此變量的引用。而對於結構體不一定。
看下面的例子:

const int j=100;    int *p=const_cast<int*>(&j);    *p=200;    cout<<j<<endl;    輸出爲什麼是100呢?

cout<<*p<<endl; //輸出是改過的200

編譯器在優化代碼時把cout<<j直接優化成cout<<100了,所以雖然p和&j的值一樣,但cout<<j不再通過訪問j的地址輸出。(反彙編時也有看到直接把數字壓棧push 100 )

這是因爲,const型在壓棧時,是使用的直接的數,就有點像C的#define a 100

對於非系統缺省類型,系統不知道怎麼去直接替換,因此必須佔據內存。

#include <iostream> using namespace std; struct A {    int i;    char ch;    A()    {        i = 100;        ch = 'S';    } }; int main() {    const A a;    const int i = 200;    int *p1 = (int*)&a.i;    int *p2 = (int*)&i;    *p1 = 1;    *p2 = 2; //   a.i = 200; //報錯,左值不能爲const    cout << a.i << " " << a.ch << endl;    cout << i << endl;    return 0; }

運行結果:

1 S 200

9.volatile的含義。
變量可能在編譯器的控制或監控之外改變,告訴編譯器不要優化該變量,如被系統時鐘更新的變量。

10.OFFSETOF(s, m)的宏定義,s是結構類型,m是s的成員,求m在s中的偏移量。
#define OFFSETOF(s, m) size_t(&((s*)0)->m)

11.100億個數,求最大的1萬個數,並說出算法的時間複雜度。
小根堆來實現。注意是小根堆,
讀入1萬個數,然後做
時間複雜度是O(NlogK)
12.設計一個洗牌的算法,並說出算法的時間複雜度。
第一種: for i:=1 to n do swap(a[i], a[random(1,n)]);  // 湊合,但不是真正隨機
第二種: for i:=1 to n do swap(a[i], a[random(i,n)]);   // 真正的隨機算法
其中,random(a,b)函數用於返回一個從a到b(包括a和b)的隨機整數。
至於怎麼證明上兩個算法,沒想好。
算法複雜度是O(n。。。),要研究下random的實現。
 
13.socket在什麼情況下可讀?
1. 接收緩衝區有數據,一定可讀 2. 對方正常關閉socket,也是可讀 3. 對於偵聽socket,有新連接到達也可讀
4.socket有錯誤發生,且pending~~~

引用unp的一段話 第六章 6.3節   
A socket is ready for reading if any of the following four conditions is true:
a. The number of bytes of data in the socket receive buffer is greater than or 
     equal to the current size of the low-water mark for the socket receive buffer.
     A read operation on the socket will not block and will return a value greater than 0
b.  The read half of the connections is closed (i.e., A TCP connection that has received a FIN).
     A read operation on the socket will not block and will return 0 (i.e., EOF)
c. The socket is a listening socket and the number of completed connection is nonzero. 
    An accept on the listening socket will normally not block, although we will describe a   
d. A socket error is pending. A read operation on the socket will not block and will return
    an error (-1) with errno set to the specific error condition

14.流量控制與擁塞控制的區別,節點計算機怎樣感知網絡擁塞了???
擁塞控制是把整體看成一個處理對象的,流量控制是對單個的節點。
感知的手段應該不少,比如在TCP協議裏,TCP報文的重傳本身就可以作爲擁塞的依據。依據這樣的原理, 應該可以設計出很多手段。
 
15.C++虛函數是如何實現的???
使用虛函數表。 C++對象使用虛表, 如果是基類的實例,對應位置存放的是基類的函數指針;如果是繼承類,對應位置存放的是繼承類的函數指針(如果在繼承類有實現)。所以 ,當使用基類指針調用對象方法時,也會根據具體的實例,調用到繼承類的方法。 
 
16.C++的虛函數有什麼作用? ??
虛函數作用是實現多態,
更重要的,虛函數其實是實現封裝,使得使用者不需要關心實現的細節。
在很多設計模式中都是這樣用法,例如Factory、Bridge、Strategy模式。 

17. 非阻塞connect()如何實現? ??
將socket設置成non-blocking,操作方法同非阻塞read()、write();
18. 以下代碼輸出結果:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("call execl"); 
sleep(1); 
execl("/bin/sh", "", NULL); 
printf("error!\n");
}
本題考標準IO緩衝,標準出錯是不帶緩緩衝的。
如若是涉及終端設備的其他流,則他們是行緩衝的;否則是全緩衝的。

printf是標準IO的一個,格式化打印到標準輸出,在這裏是行緩衝,那麼沒有遇到換行符也就是‘\n’或者沒有強制flush, 則不會輸出。
execl是創建新的可執行程序映像,一旦成功就不會返回了,只有在出錯的情況會返回1.
所以以上的程序沒有打印printf的內容,直接執行/bin/sh,輸出爲
$

若是代碼改爲以下:
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    printf("call execl\n");
    /*fprintf(stderr, "%s", "call execl");*/
    sleep(1);
    execl("/bin/sh", "", NULL);
    printf("error!\n");

    return 0;
}
則輸出爲:
call execl
$

若改爲:
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    /*printf("call execl\n");*/
    fprintf(stderr, "%s", "call execl");       // 標準錯誤,不緩衝
    sleep(1);
    execl("/bin/sh", "", NULL);
    printf("error!\n");

    return 0;
}
則輸出爲:
call execl$

若改爲:
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    /*printf("call execl\n");*/
    fprintf(stdout, "%s", "call execl");     // stdout行緩衝
    sleep(1);
    execl("/bin/sh", "", NULL);
    printf("error!\n");

    return 0;
}
則輸出爲
$

19. TCP通訊中,select到讀事件,但是讀到的數據量是0,爲什麼,如何解決????
select 返回0代表超時。select出錯返回-1。

select到讀事件,但是讀到的數據量爲0,說明對方已經關閉了socket的讀端。本端關閉讀即可。

當select出錯時,會將接口置爲可讀又可寫。這時就要通過判斷select的返回值爲-1來區分。

20. 給出float與“零值”比較的 if 語句(假設變量名爲var)???
const float EPSINON = 0.00001;
  if ((x >= - EPSINON) && (x <= EPSINON)

浮點數在內存中的存貯機制和整型數不同,有舍入誤差在計算機中用以近似表示任意某個實數。具體的說,這個實數由一個整數或定點數(即尾數)乘以某個基數(計算機中通常是2)的整數次冪得到,這種表示方法類似於基數爲10的科學記數法。
  所以浮點數在運算過成功運算通常伴隨着因爲無法精確表示而進行的近似或舍入。但是這種設計的好處是可以在固定的長度上存儲更大範圍的數。
  例如,一個指數範圍爲±4的4位十進制浮點數可以用來表示43210,4.321或0.0004321,但是沒有足夠的精度來表示432.123和43212.3(必須近似爲432.1和43210)。當然,實際使用的位數通常遠大於4。  
  所以浮點數不能夠判斷相等像 if(x==0)的這樣的編碼是不總是正確的,我們在判斷浮點數相等時,推薦用範圍來確定,若x在某一範圍內,我們就認爲相等,至於範圍怎麼定義,要看實際情況而已了,float,和double 各有不同
  所以const float EPSINON = 0.00001;  
  if ((x >= - EPSINON) && (x <= EPSINON) 這樣判斷是可取的
  至於爲什麼取0.00001,可以自己按實際情況定義


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章