1. 程式人生 > 實用技巧 >AF_INET與套接字

AF_INET與套接字

建立套接字的函式是socket(),函式原型為:

 #include <sys/types.h>
 #include <sys/socket.h>
     int socket(int domain, int type, int protocol);

其中“int domain”引數表示套接字要使用的協議簇,協議簇的在“linux/socket.h”裡有詳細定義,常用的協議簇:

  • AF_UNIX(本機通訊)
  • AF_INET(TCP/IP-IPv4)
  • AF_INET6(TCP/IP-IPv6)

其中“type”引數指的是套接字型別,常用的型別有:

  • SOCK_STREAM(TCP流)
  • SOCK_DGRAM(UDP資料報)
  • SOCK_RAW(原始套接字)

最後一個“protocol”一般設定為“0”,也就是當確定套接字使用的協議簇和型別時,這個引數的值就為0,但是有時候建立原始套接字時,並不知道要使用的協議簇和型別,也就是domain引數未知情況下,這時protocol這個引數就起作用了,它可以確定協議的種類。
socket是一個函式,那麼它也有返回值,當套接字建立成功時,返回套接字,失敗返回“-1”,錯誤程式碼則寫入“errno”中。
建立套接字:

python中socket預設為Ipv4,tcp模式。
服務端

sock =socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((ip,port))
#繫結ip和埠號 sock.listen(5)#開啟監聽,允許5個連線, while True: conn,addr = sock.accept() buf = conn.recv(1024) if len(buf): print(buf)
     conn.send(buf) sock.close()

listen引數的問題

可以表示可建立socket連線的排隊的個數

windows,mac此連線引數有效

Linux此連線引數無效,預設最大

客戶端

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip,port))#監聽ip和埠號
sock.send(messages)
while True:
    buf = sock.recv(1024)#一次接受1024位元組資料
    if len(buf):
        print(buf)
sock.close()

socket程式設計中主動關閉和被動關閉

tcp中server,client都可能是主動關閉方或者被動關閉方,現闡述下兩者之間的關係:

客戶端(client) 伺服器(server)

close() Fin x -> 讀通道關閉(close_wait)

寫通道關閉 <- Ack x+1

讀通道關閉(time_wait) <- Fin y close()

ack y+1 -> 寫通道關閉

2x msl closed

closed

  1. 客戶端呼叫函式close(),這時,客戶端會發送一個FIN訊號給伺服器
  2. 伺服器收到FIN訊號,關閉套接字的讀通道,並將自己的狀態設定為CLOSE_WAIT(表示被動關閉),並返回一個ACK給客戶端
  3. 客戶端收到ACK,關閉套接字寫通道
  4. 接下來伺服器會呼叫close():
  5. 伺服器close(),傳送一個FIN到客戶端。
  6. 客戶端收到FIN,關閉讀通道,並將自己的狀態設定成TIME_WAIT,傳送一個ACK給伺服器
  7. 伺服器收到ACK,關閉寫通道,並將自己的狀態設定為CLOSE。
  8. 客戶端等待兩個最大資料傳輸時間,然後將自己的狀態設定成CLOSED。

有了上面的背景知識,對於我們系統線上一個case分析就很簡單了!

首先是主動關閉日誌很多,後來是被動關閉的日誌

由於server端發現了大量閒置的沒有Io的socket連線,有監聽器在監聽是否存在閒置的socket連線,就釋放並關閉這些連線,time_wait就出現了,這個時候應用方客戶端重啟應用,釋放了資源包括一些客戶端連線,這個時候close_wait出現了,正好是以上日誌所反映的

同時time_wait狀態的連線是不會釋放核心資源,所以服務端不要輕易close!

socket是全雙工管道,雖然只有一對socket,但實際上是兩個通道,讀寫是不會衝突的。

python 解決close_wait過多問題

close_wait產生的原因:

首先要知道客戶端和服務端的連線是使用套接字通訊的,TCP/IP協議建立連線需要三次握手,而關閉client與server的連線需要進行四步,如圖:

建立連線後常用的三個狀態是:ESTABLISHED 表示正在通訊,TIME_WAIT 表示主動關閉,CLOSE_WAIT 表示被動關閉。

通過上圖,我們來分析,什麼情況下,連線處於CLOSE_WAIT狀態呢?

就是服務端在被動關閉收到FIN,未發出自己FIN的情況下就處於CLOSE_WAIT狀態了,通常CLOSE_WAIT的持續時間很

短,但是在某些特殊狀態下就可能長時間存在,如果出現大量close_wait的現象,主要原因可能是一方關閉了socket連結,但是另一方

忙與讀或者寫,沒有關閉連線。程式碼需要判斷socket,一旦讀到0,斷開連線,read返回負,檢查一下errno(errno是記錄系統的最後

一次錯誤程式碼。),如果不是AGAIN,就斷開連線。

本文部分摘自:https://www.cnblogs.com/leijiangtao/p/11883310.html