国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
linux socket
(轉(zhuǎn))Linux socket 編程中存在的五個(gè)隱患
2008年01月26日 星期六 19:32
前言:
        Socket API 是網(wǎng)絡(luò)應(yīng)用程序開發(fā)中實(shí)際應(yīng)用的標(biāo)準(zhǔn) API。盡管該 API 簡單,但是開發(fā)新手可能會經(jīng)歷一些常見的問題。本文識別一些最常見的隱患并向您顯示如何避免它們。
  在 4.2 BSD UNIX® 操作系統(tǒng)中首次引入,Sockets API 現(xiàn)在是任何操作系統(tǒng)的標(biāo)準(zhǔn)特性。事實(shí)上,很難找到一種不支持 Sockets API 的現(xiàn)代語言。該 API 相當(dāng)簡單,但新的開發(fā)人員仍然會遇到一些常見的隱患。
  本文識別那些隱患并向您顯示如何避開它們。
隱患 1.忽略返回狀態(tài)
第一個(gè)隱患很明顯,但它是開發(fā)新手最容易犯的一個(gè)錯(cuò)誤。如果您忽略函數(shù)的返回狀態(tài),當(dāng)它們失敗或部分成功的時(shí)候,您也許會迷失。反過來,這可能傳播錯(cuò)誤,使定位問題的源頭變得困難。
捕獲并檢查每一個(gè)返回狀態(tài),而不是忽略它們。考慮清單 1 顯示的例子,一個(gè)套接字 send 函數(shù)。
清單 1. 忽略 API 函數(shù)返回狀態(tài)
int status, sock, mode;
/* Create a new stream (TCP) socket */
sock = socket( AF_INET, SOCK_STREAM, 0 );
...status = send( sock, buffer, buflen, MSG_DONTWAIT );
if (status == -1)
{ /* send failed */
printf( "send failed: %s\n",?
strerror(errno) );
}
else
{ /* send succeeded -- or did it? */}           
  清單 1 探究一個(gè)函數(shù)片斷,它完成套接字 send 操作(通過套接字發(fā)送數(shù)據(jù))。函數(shù)的錯(cuò)誤狀態(tài)被捕獲并測試,但這個(gè)例子忽略了 send 在無阻塞模式(由 MSG_DONTWAIT 標(biāo)志啟用)下的一個(gè)特性。
  send API 函數(shù)有三類可能的返回值:
  • 如果數(shù)據(jù)成功地排到傳輸隊(duì)列,則返回 0。
  • 如果排隊(duì)失敗,則返回 -1(通過使用 errno 變量可以了解失敗的原因)。
  • 如果不是所有的字符都能夠在函數(shù)調(diào)用時(shí)排隊(duì),則最終的返回值是發(fā)送的字符數(shù)。
  由于 send 的 MSG_DONTWAIT 變量的無阻塞性質(zhì),函數(shù)調(diào)用在發(fā)送完所有的數(shù)據(jù)、一些數(shù)據(jù)或沒有發(fā)送任何數(shù)據(jù)后返回。在這里忽略返回狀態(tài)將導(dǎo)致不完全的發(fā)送和隨后的數(shù)據(jù)丟失。
隱患 2.對等套接字閉包
UNIX 有趣的一面是您幾乎可以把任何東西看成是一個(gè)文件。文件本身、目錄、管道、設(shè)備和套接字都被當(dāng)作文件。這是新穎的抽象,意味著一整套的 API 可以用在廣泛的設(shè)備類型上。
考慮 read API 函數(shù),它從文件讀取一定數(shù)量的字節(jié)。read 函數(shù)返回讀取的字節(jié)數(shù)(最高為您指定的最大值);或者 -1,表示錯(cuò)誤;或者 0,如果已經(jīng)到達(dá)文件末尾。
如果在一個(gè)套接字上完成一個(gè) read 操作并得到一個(gè)為 0 的返回值,這表明遠(yuǎn)程套接字端的對等層調(diào)用了 close API 方法。該指示與文件讀取相同 —— 沒有多余的數(shù)據(jù)可以通過描述符讀?。▍⒁?清單 2)。
清單 2.適當(dāng)處理 read API 函數(shù)的返回值
int sock, status;
sock = socket( AF_INET, SOCK_STREAM, 0 );
...status = read( sock, buffer, buflen );
if (status > 0)
{ /* Data read from the socket */}
else if (status == -1)
{
/* Error, check errno, take action... */
}
else if (status == 0)
{
/* Peer closed the socket, finish the close */
close( sock );
/* Further processing... */
}
  同樣,可以用 write API 函數(shù)來探測對等套接字的閉包。在這種情況下,接收 SIGPIPE 信號,或如果該信號阻塞,write 函數(shù)將返回 -1 并設(shè)置 errno 為 EPIPE。
隱患 3.地址使用錯(cuò)誤(EADDRINUSE)
  您可以使用 bind API 函數(shù)來綁定一個(gè)地址(一個(gè)接口和一個(gè)端口)到一個(gè)套接字端點(diǎn)。可以在服務(wù)器設(shè)置中使用這個(gè)函數(shù),以便限制可能有連接到來的接口。也可以在客戶端設(shè)置中使用這個(gè)函數(shù),以便限制應(yīng)當(dāng)供出去的連接所使用的接口。bind 最常見的用法是關(guān)聯(lián)端口號和服務(wù)器,并使用通配符地址(INADDR_ANY),它允許任何接口為到來的連接所使用。
  bind 普遍遭遇的問題是試圖綁定一個(gè)已經(jīng)在使用的端口。該陷阱是也許沒有活動的套接字存在,但仍然禁止綁定端口(bind 返回 EADDRINUSE),它由 TCP 套接字狀態(tài) TIME_WAIT 引起。該狀態(tài)在套接字關(guān)閉后約保留 2 到 4 分鐘。在 TIME_WAIT 狀態(tài)退出之后,套接字被刪除,該地址才能被重新綁定而不出問題。
等待 TIME_WAIT 結(jié)束可能是令人惱火的一件事,特別是如果您正在開發(fā)一個(gè)套接字服務(wù)器,就需要停止服務(wù)器來做一些改動,然后重啟。幸運(yùn)的是,有方法可以避開 TIME_WAIT 狀態(tài)??梢越o套接字應(yīng)用 SO_REUSEADDR 套接字選項(xiàng),以便端口可以馬上重用。
考慮清單 3 的例子。在綁定地址之前,我以 SO_REUSEADDR 選項(xiàng)調(diào)用 setsockopt。為了允許地址重用,我設(shè)置整型參數(shù)(on)為 1 (不然,可以設(shè)為 0 來禁止地址重用)。
清單 3.使用 SO_REUSEADDR 套接字選項(xiàng)避免地址使用錯(cuò)誤
int sock, ret, on;struct sockaddr_in servaddr;
/* Create a new stream (TCP) socket */
sock = socket( AF_INET, SOCK_STREAM, 0 ):
/* Enable address reuse */
on = 1;
ret = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR,
&on, sizeof(on) );
/* Allow connections to port 8080 from any available interface
*/
memset( &servaddr, 0, sizeof(servaddr) );
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl( INADDR_ANY );
servaddr.sin_port = htons( 45000 );
/* Bind to the address (interface/port) */
ret = bind( sock, (struct sockaddr *)&servaddr, sizeof(servaddr) );     
在應(yīng)用了 SO_REUSEADDR 選項(xiàng)之后,bind API 函數(shù)將允許地址的立即重用。
隱患 4.發(fā)送結(jié)構(gòu)化數(shù)據(jù)
套接字是發(fā)送無結(jié)構(gòu)二進(jìn)制字節(jié)流或 ASCII 數(shù)據(jù)流(比如 HTTP 上的 HTTP 頁面,或 SMTP 上的電子郵件)的完美工具。但是如果試圖在一個(gè)套接字上發(fā)送二進(jìn)制數(shù)據(jù),事情將會變得更加復(fù)雜。
  比如說,您想要發(fā)送一個(gè)整數(shù):您可以肯定,接收者將使用同樣的方式來解釋該整數(shù)嗎?運(yùn)行在同一架構(gòu)上的應(yīng)用程序可以依賴它們共同的平臺來對該類型的數(shù)據(jù)做出相同的解釋。但是,如果一個(gè)運(yùn)行在高位優(yōu)先的 IBM PowerPC 上的客戶端發(fā)送一個(gè) 32 位的整數(shù)到一個(gè)低位優(yōu)先的 Intel x86,那將會發(fā)生什么呢?字節(jié)排列將引起不正確的解釋。
  通過套接字發(fā)送一個(gè) C 結(jié)構(gòu)會怎么樣呢?這里,也會遇到麻煩,因?yàn)椴皇撬械木幾g器都以相同的方式排列一個(gè)結(jié)構(gòu)的元素。結(jié)構(gòu)也可能被壓縮以便使浪費(fèi)的空間最少,這進(jìn)一步使結(jié)構(gòu)中的元素錯(cuò)位。
  幸好,有解決這個(gè)問題的方案,能夠保證兩端數(shù)據(jù)的一致解釋。過去,遠(yuǎn)程過程調(diào)用(Remote Procedure Call,RPC)套裝工具提供所謂的外部數(shù)據(jù)表示(External Data Representation,XDR)。XDR 為數(shù)據(jù)定義一個(gè)標(biāo)準(zhǔn)的表示來支持異構(gòu)網(wǎng)絡(luò)應(yīng)用程序通信的開發(fā)。
現(xiàn)在,有兩個(gè)新的協(xié)議提供相似的功能。可擴(kuò)展標(biāo)記語言/遠(yuǎn)程過程調(diào)用(XML/RPC)以 XML 格式安排 HTTP 上的過程調(diào)用。數(shù)據(jù)和元數(shù)據(jù)用 XML 進(jìn)行編碼并作為字符串傳輸,并通過主機(jī)架構(gòu)把值和它們的物理表示分開。SOAP 跟隨 XML-RPC,以更好的特性和功能擴(kuò)展了它的思想。參見 參考資料小節(jié),獲取更多關(guān)于每個(gè)協(xié)議的信息。
隱患 5.TCP 中的幀同步假定
TCP 不提供幀同步,這使得它對于面向字節(jié)流的協(xié)議是完美的。這是 TCP 與 UDP(User Datagram Protocol,用戶數(shù)據(jù)報(bào)協(xié)議)的一個(gè)重要區(qū)別。UDP 是面向消息的協(xié)議,它保留發(fā)送者和接收者之間的消息邊界。TCP 是一個(gè)面向流的協(xié)議,它假定正在通信的數(shù)據(jù)是無結(jié)構(gòu)的,如圖 1 所示。
圖 1.UDP 的幀同步能力和缺乏幀同步的 TCP
  圖 1 的上部說明一個(gè) UDP 客戶端和服務(wù)器。左邊的對等層完成兩個(gè)套接字的寫操作,每個(gè) 100 字節(jié)。協(xié)議棧的 UDP 層追蹤寫的數(shù)量,并確保當(dāng)右邊的接收者通過套接字獲取數(shù)據(jù)時(shí),它以同樣數(shù)量的字節(jié)到達(dá)。換句話說,為讀者保留了寫者提供的消息邊界。
現(xiàn)在,看圖 1 的底部.它為 TCP 層演示了相同粒度的寫操作。兩個(gè)獨(dú)立的寫操作(每個(gè) 100 字節(jié))寫入流套接字。但在本例中,流套接字的讀者得到的是 200 字節(jié)。協(xié)議棧的 TCP 層聚合了兩次寫操作。這種聚合可以發(fā)生在 TCP/IP 協(xié)議棧的發(fā)送者或接收者中任何一方。重要的是,要注意到聚合也許不會發(fā)生 —— TCP 只保證數(shù)據(jù)的有序發(fā)送。
  對大多數(shù)開發(fā)人員來說,該陷阱會引起困惑。您想要獲得 TCP 的可靠性和 UDP 的幀同步。除非改用其他的傳輸協(xié)議,比如流傳輸控制協(xié)議(STCP),否則就要求應(yīng)用層開發(fā)人員來實(shí)現(xiàn)緩沖和分段功能。
  調(diào)試套接字應(yīng)用程序的工具
  GNU/Linux 提供幾個(gè)工具,它們可以幫助您發(fā)現(xiàn)套接字應(yīng)用程序中的一些問題。此外,使用這些工具還有教育意義,而且能夠幫助解釋應(yīng)用程序和 TCP/IP 協(xié)議棧的行為。在這里,您將看到對幾個(gè)工具的概述。查閱下面的 參考資料 了解更多的信息。
  查看網(wǎng)絡(luò)子系統(tǒng)的細(xì)節(jié)
  netstat 工具提供查看 GNU/Linux 網(wǎng)絡(luò)子系統(tǒng)的能力。使用 netstat,可以查看當(dāng)前活動的連接(按單個(gè)協(xié)議進(jìn)行查看),查看特定狀態(tài)的連接(比如處于監(jiān)聽狀態(tài)的服務(wù)器套接字)和許多其他的信息。清單 4 顯示了 netstat 提供的一些選項(xiàng)和它們啟用的特性。

清單 4.netstat 實(shí)用程序的用法模式
View all TCP sockets currently active$ netstat
--tcpView all UDP sockets$ netstat
--udpView all TCP sockets in the listening state$ netstat
--listeningView the multicast group membership information$ netstat
--groupsDisplay the list of masqueraded connections$ netstat
--masqueradeView statistics for each protocol$ netstat
--statistics
  盡管存在許多其他的實(shí)用程序,但 netstat 的功能很全面,它覆蓋了 route、ifconfig 和其他標(biāo)準(zhǔn) GNU/Linux 工具的功能。
  監(jiān)視流量
  可以使用 GNU/Linux 的幾個(gè)工具來檢查網(wǎng)絡(luò)上的低層流量。tcpdump 工具是一個(gè)比較老的工具,它從網(wǎng)上“嗅探”網(wǎng)絡(luò)數(shù)據(jù)包,打印到 stdout 或記錄在一個(gè)文件中。該功能允許查看應(yīng)用程序產(chǎn)生的流量和 TCP 生成的低層流控制機(jī)制。一個(gè)叫做 tcpflow 的新工具與 tcpdump 相輔相成,它提供協(xié)議流分析和適當(dāng)?shù)刂貥?gòu)數(shù)據(jù)流的方法,而不管數(shù)據(jù)包的順序或重發(fā)。清單 5 顯示 tcpdump 的兩個(gè)用法模式。

  清單 5.tcpdump 工具的用法模式
Display all traffic on the eth0 interface for
the local host$ tcpdump -l -i eth0Show all traffic
on the network coming from or going
to host plato$ tcpdump host platoShow all HTTP traffic
for host camus$ tcpdump host camus and (port http)View
traffic coming from or going
to TCP port 45000 on the local host$ tcpdump tcp port 45000
tcpdump tcpflow 工具有大量的選項(xiàng),包括創(chuàng)建復(fù)雜過濾表達(dá)式的能力。查閱下面的參考資料 獲取更多關(guān)于這些工具的信息。
tcpdump tcpflow 都是基于文本的命令行工具。如果您更喜歡圖形用戶界面(GUI),有一個(gè)開放源碼工具 Ethereal 也許適合您的需要。Ethereal 是一個(gè)專業(yè)的協(xié)議分析軟件,它可以幫助調(diào)試應(yīng)用層協(xié)議。它的插入式架構(gòu)(plug-in architecture)可以分解協(xié)議,比如 HTTP 和您能想到的任何協(xié)議(寫本文的時(shí)候共有 637 個(gè)協(xié)議)。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Windows Sockets API實(shí)現(xiàn)網(wǎng)絡(luò)異步通訊 | VC | 軟件 | 天極Yes...
python網(wǎng)絡(luò)編程及socket模塊簡析
LWIP之SOCKET的實(shí)現(xiàn)
[精通WindowsSocket網(wǎng)絡(luò)開發(fā)
從零開始的C 網(wǎng)絡(luò)編程
原始套接字
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服