阻塞與非阻塞我的小結

1.connect函數響應中斷返回後仍然回到函數的調用。
       實踐證實,對於一個非阻塞的socket,若是在調用connect函數時,若是發生中斷,這函數響應中斷,但當中斷返回時,繼續connect函數的調用,直到connect超時失敗或接收到錯誤ICMP包或鏈接成功服務器

        2.accept()
        若是偵聽進程是非阻塞模式工做,當調用accept()函數接收來自客戶端的請求後,返回的socket套接字,默認爲阻塞的工做模式。網絡

1、阻塞模型
    可能發生阻塞的套接口調用分爲四種:
    1>.輸入操做:read、readv、recv、recvfrom和recvmsg函數
    2>.輸出操做:write、writev、send、sendto和sendmsg函數
    3>.接收外來鏈接:accept()函數
    4>.初始化外出的鏈接:connect()函數數據結構

2、I/O模型
    1.阻塞I/O
    2.非阻塞I/O
    3.I/O複用(select函數)
    4.信號驅動I/O(SIGIO)
    5.異步I/O異步

3、I/O複用模型的應用場合
    1.當客戶處理多個描述字時(通常是交互式輸入和網絡套接口),必須使用I/O複用。
    2.一個客戶同時處理多個套接口
    3.若是一個TCP服務器既要處理偵聽套接口,又要處理已鏈接套接口,通常也要用到I/O複用。
    4.若是一個服務器既要處理TCP,又要處理UDP,通常也要使用I/O複用。
    5.若是一個服務器要處理多個服務或者多個協議(inetd守護進程)。socket

4、拒絕服務型攻擊
    服務器某一個時刻阻塞於只處理單個客戶,而不能處理其餘客戶的需求,這就致使了拒絕服務型攻擊,可能的解決辦法是:(a)使用非阻塞I/O模型;(b)讓 每一個客戶由單獨的控制線程提供服務(例如,建立子進程或線程來爲每一個客戶提供服務);(c)對I/O操做設置超時。函數

5、connect()函數
    
1.阻塞模式
    客戶端調用connect()函數將激發TCP的三路握手過程,但僅在鏈接創建成功或出錯時才返回。返回的錯誤可能有如下幾種狀況:
    1>.若是TCP客戶端沒有接收到SYN分節的響應,則返回ETIMEDOUT,阻塞模式的超時時間在75秒(4.4BSD內核)到幾分鐘之間。
    2>.若是對客戶的SYN的響應時RST,則代表該服務器主機在咱們指定的端口上沒有進程在等待與之鏈接(例如服務器進程也許沒有啓動),這稱爲硬錯,客戶一接收到RST,立刻就返回錯誤ECONNREFUSED.
    3>.若是某客戶發出的SYN在中間的路由器上引起了一個目的地不可達ICMP錯誤,屢次嘗試發送失敗後返回錯誤號爲EHOSTUNREACH或ENETUNREACH.spa

附加:產生RST的三種狀況,一是SYN到達某端口但此端口上沒有正在偵聽的服務器、二是TCP想取消一個已有鏈接、三是TCP接收了一個根本不存在的鏈接上的分節。線程

2.非阻塞模式
    採用非阻塞的工做模式要考慮一下兩種狀況:
1>.若是是鏈接本機,則調用connect()函數會馬上創建。
2>.若是服務器是網絡中的用戶,則調用connect()函數須要從幾個毫秒的局域網到幾百毫秒或幾秒的廣域網。而且函數會馬上返回EINPROCESS錯誤,但TCP通訊的三路握手過程正在進行,因此可使用select函數來檢查這個鏈接是否創建成功。
    源自Berkeley的實現有兩條與select函數和非阻塞相關的規則:
1>.當鏈接成功創建時,描述字變成可寫。
2>.當鏈接創建出錯時,描述字變成便可讀又可寫。code

6、accept()函數
1.阻塞模式
    若是在一個阻塞套接口上調用accept()函數,並且沒有新的鏈接,進程會進入睡眠狀態。orm

2.非阻塞模式
    若是在一個非阻塞套接口上調用accept()函數,並且沒有新的鏈接,將返回EWOULDBLOCK錯誤。

3.一種非阻塞模式例子的問題及解決辦法
    問題描述:在服務器端偵聽套接口採用阻塞的方式工做,而且使用select檢測是否有已經創建起的鏈接,若是有則調用accept()函數接收該鏈接,問 題是若是客戶端首先調用connect()函數鏈接服務器後馬上又調用close()函數關閉該鏈接,而在服務器端,在select()函數返回和調用 accept()函數之間,接收到客戶端的斷開,則會刪除該套接口在已鏈接套接口中的內容,因此服務器將會阻塞在accept()函數,直到有客戶鏈接才 返回。
    解決辦法:(1).若是用select來獲知什麼時候有鏈接已就緒能夠accept時,老是把偵聽套接口置爲非阻塞,同時(2).在後面的accept調用中 忽略如下錯誤:EWOULDBLOCK(Berkeley的實如今客戶放棄鏈接時出現的錯誤)、ECONNABORTED(Posix.1g的實如今客戶 放棄鏈接時出現的錯誤)、EPROTO(SVR4的實如今客戶放棄鏈接時出現的錯誤)和EINTR(若是信號被捕獲)。

7、select()函數
    select()函數準備好讀的條件:
    1>.套接口有數據可讀
    2>.該鏈接的讀這一半關閉(也就是接收了FIN的TCP鏈接)。對這樣的套接口進行讀操做將不阻塞並返回0(也就是返回EOF)。
    3>.該套接口是一個偵聽套接口且已完成的鏈接數不爲0。
    4>.其上有一個套接口錯誤待處理,對這樣的套接口的讀操做將不阻塞並返回-1,並設置errno,能夠經過設置SO_ERROR選項調用getsockopt函數得到。

    select()函數準備好寫的條件:
    1>.套接口有可用於寫的空間。
    2>.該鏈接的寫這一半關閉,對這樣的套接口進行寫操做將產生SIGPIPE信號。
    3>.該套接口使用非阻塞的方式connect創建鏈接,而且鏈接已經異步創建,或則connect已經以失敗了結。
    4>.其上有一個套接口錯誤待處理。

8、read()函數和recv函數
    read()函數返回值表明的意義:
    1>.若是對方TCP發送數據,則套接口就變爲可讀且read返回大於0的值(即數據的字節數)。
    2>.若是對方TCP發送一個FIN(對方進程終止),套接口就變爲可讀且read返回0(文件結束)。
    3>.若是對方TCP發送一個RST(對方主機崩潰並從新啓動),套接口就變成可讀且read返回-1,返回的錯誤號errno爲ECONNRESET。


9、write()函數和send函數
    若是向一個接收了FIN的套接字進行寫操做是可行的,但若是向一個接受了RST的套接字進行寫操做則是致命的,內核會向該進程發送一個SIGPIPE信號,返回EPIPO,該錯誤類型默認爲終止進程。


SIGPIPE信號
    向一個接受了RST的套接字進行寫操做時,內核會向該進程發送一個SIGPIPE信號,該信號的缺省行爲是終止進程,所以進程必須捕獲它以避免被不情願的終止。
   


五、 Linux中Socket的數據結構
(1)

struct sockaddr { //用於存儲套接字地址
    unsigned short sa_family;//地址類型
    char sa_data[14]; //14字節的協議地址
};

(2)

struct sockaddr_in{ //in 表明internet
    short int sin_family; //internet協議族
    unsigned short int sin_port;//端口號,必須是網絡字節順序
    struct in_addr sin_addr;//internet地址,必須是網絡字節順序
    unsigned char sin_zero;//添0(和struct sockaddr同樣大小
};

(3)

 struct in_addr{
    unsigned long s_addr;
};
相關文章
相關標籤/搜索