国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python中基礎的socket編程實戰攻略

2019-11-25 16:46:14
字體:
來源:轉載
供稿:網友

在網絡通信中socket幾乎無處不在,它可以看成是應用層與TCP/IP協議簇通信的中間軟件抽象層,是兩個應用程序彼此進行通信的接口,并且把復雜的TCP/IP協議細節隱藏在接口之后。Python提供了socket模塊,可以非常方便的進行socket編程。

創建一個server socket
使用socket方法創建一個新的socket,通常提供兩個參數,第一個參數是address family, 第二個是socket type。

#create an INET, STREAMing sockets = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

以上創建了一個address family為IP協議,并且傳輸協議為TCP的socket。

服務器端在創建一個socket之后,需要綁定到一個IP地址與端口,提供服務,這就要用到bind方法。

# bind the socket to all available interfaces on port 8888s.bind(('', 8888))

使用listen方法,將socket設置為監聽狀態。listen方法后面跟一個參數,表示最多可以在隊列里面接收的請求數目。

#become a server socketserversocket.listen(5)

現在,我們已經創建了一個server socket,然后編寫一個無限循環體,接收來自客戶端的連接,利用accept方法,它返回一個新的socket,表示與遠端的連接,同時返回一個地址對,表示遠端連接的IP地址與端口號。

# enter the main loop of the web serverwhile 1:  #accept connections from outside, return a pair (conn, addr)  (clientsocket, address) = serversocket.accept()  #now do something with the clientsocket  #in this case, we'll pretend this is a threaded server  ct = client_thread(clientsocket)  ct.run()

通常,循環體中的server socket不會發送和接收任何數據,而僅僅是接收來自遠端的連接,將新的連接交給其他的線程去處理,然后就繼續偵聽更多其他的連接,否則的話在處理一個連接的時候,就無法接受其他新的連接了。

接下來,我們新建一個線程對連接進行處理。首先,使用recv方法接受來自socket的數據,后面帶著一個參數表示一次最多可以接受數據的大小。然后使用sendall方法回復socket,sendall不斷發送數據直到所有數據發送完畢或者發生了異常。最后,需要記得把socket關閉,因為每個socket就代表了系統中的一個文件描述符,如果沒有及時關閉,可能會超過系統最大文件描述符的數量,導致無法創建新的socket。

def handle_request(sock, addr):  print "Accept new connection from {addr}".format(addr = addr)  request_data = client_connection.recv(1024)  print request_data.decode()  http_response = "Hello, world!"  # send response data to the socket  sock.sendall(http_response)  sock.close()

總結server socket主要由以下幾個步驟:

  • 創建一個新的server socket;
  • 將socket綁定到一個地址和端口;
  • 偵聽遠程進來的連接;
  • 接受連接, 分發給其他線程處理。

以下是完整的server socket示例代碼:

import socketimport threadingSERVER_ADDRESS = (HOST, PORT) = '', 8888REQUEST_QUEUE_SIZE = 1024def handle_request(sock, addr):  print "Accept new connection from {addr}".format(addr = addr)  request_data = client_connection.recv(1024)  print request_data.decode()  http_response = "Hello, world!"  # send response data to the socket  sock.sendall(http_response)  sock.close()def serve_forever():  server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # reuse socket immediately  server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  server_socket.bind(SERVER_ADDRESS)  server_socket.listen(REQUEST_QUEUE_SIZE)  print 'Serving HTTP on port {port} ...'.format(port = PORT)  while True:    try:      client_connection, client_address = server_socket.accept()    except IOError as e:      code, msg = e.args      # restart 'accept' if it was interrupted      if code == errno.EINTR:        continue      else:        raise    # create a thread to handle this request    t = threading.Thread(target=handle_request, args=(sock, addr))    t.start()if __name__ == '__main__':  serve_forever()

創建一個client socket
客戶端的socket就比較簡單,主要包括以下幾個步驟:

  • 創建一個socket;
  • 連接到服務器;
  • 給服務器發送數據;
  • 接收服務器返回的數據;
  • 關閉socket。
import socketHOST = 'localhost' # the remote hostPORT = 8888 # port used by serverclient_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# connect to serverclient_socket.connect((HOST, PORT))# send something to the serverclient_socket.sendall("Hello, world")data = client_socket.recv(1024)client_socket.close()print 'Received', repr(data)

PS:socket模塊使用引申

sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)

參數一:地址簇

  socket.AF_INET IPv4(默認)
  socket.AF_INET6 IPv6

  socket.AF_UNIX 只能夠用于單一的Unix系統進程間通信

參數二:類型

  socket.SOCK_STREAM  流式socket , for TCP (默認)
  socket.SOCK_DGRAM   數據報式socket , for UDP

  socket.SOCK_RAW 原始套接字,普通的套接字無法處理ICMP、IGMP等網絡報文,而SOCK_RAW可以;其次,SOCK_RAW也可以處理特殊的IPv4報文;此外,利用原始套接字,可以通過IP_HDRINCL套接字選項由用戶構造IP頭。
  socket.SOCK_RDM 是一種可靠的UDP形式,即保證交付數據報但不保證順序。SOCK_RAM用來提供對原始協議的低級訪問,在需要執行某些特殊操作時使用,如發送ICMP報文。SOCK_RAM通常僅限于高級用戶或管理員運行的程序使用。
  socket.SOCK_SEQPACKET 可靠的連續數據包服務

參數三:協議

  0  (默認)與特定的地址家族相關的協議,如果是 0 ,則系統就會根據地址格式和套接類別,自動選擇一個合適的協議

sk.bind(address)

  s.bind(address) 將套接字綁定到地址。address地址的格式取決于地址族。在AF_INET下,以元組(host,port)的形式表示地址。

sk.listen(backlog)

  開始監聽傳入連接。backlog指定在拒絕連接之前,可以掛起的最大連接數量。

      backlog等于5,表示內核已經接到了連接請求,但服務器還沒有調用accept進行處理的連接個數最大為5
      這個值不能無限大,因為要在內核中維護連接隊列

sk.setblocking(bool)

  是否阻塞(默認True),如果設置False,那么accept和recv時一旦無數據,則報錯。

sk.accept()

  接受連接并返回(conn,address),其中conn是新的套接字對象,可以用來接收和發送數據。address是連接客戶端的地址。

  接收TCP 客戶的連接(阻塞式)等待連接的到來

sk.connect(address)

  連接到address處的套接字。一般,address的格式為元組(hostname,port),如果連接出錯,返回socket.error錯誤。

sk.connect_ex(address)

  同上,只不過會有返回值,連接成功時返回 0 ,連接失敗時候返回編碼,例如:10061

sk.close()

  關閉套接字

sk.recv(bufsize[,flag])

  接受套接字的數據。數據以字符串形式返回,bufsize指定最多可以接收的數量。flag提供有關消息的其他信息,通常可以忽略。

sk.recvfrom(bufsize[.flag])

  與recv()類似,但返回值是(data,address)。其中data是包含接收數據的字符串,address是發送數據的套接字地址。

sk.send(string[,flag])

  將string中的數據發送到連接的套接字。返回值是要發送的字節數量,該數量可能小于string的字節大小。

sk.sendall(string[,flag])

  將string中的數據發送到連接的套接字,但在返回之前會嘗試發送所有數據。成功返回None,失敗則拋出異常。

sk.sendto(string[,flag],address)

  將數據發送到套接字,address是形式為(ipaddr,port)的元組,指定遠程地址。返回值是發送的字節數。該函數主要用于UDP協議。

sk.settimeout(timeout)

  設置套接字操作的超時期,timeout是一個浮點數,單位是秒。值為None表示沒有超時期。一般,超時期應該在剛創建套接字時設置,因為它們可能用于連接的操作(如 client 連接最多等待5s )

sk.getpeername()
    這個方法只能用在客戶端,用于查看server端的信息
  返回連接套接字的遠程地址。返回值通常是元組(ipaddr,port)。

sk.getsockname()
    這個方法只能用在server端用與查看server端自己的信息
  返回套接字自己的地址。通常是一個元組(ipaddr,port)

sk.fileno()

  套接字的文件描述符

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 沧源| 韶山市| 高阳县| 寻乌县| 玉门市| 岚皋县| 信丰县| 高要市| 福泉市| 从江县| 崇明县| 宁陵县| 临沂市| 齐齐哈尔市| 阿拉善盟| 晋江市| 岗巴县| 枣庄市| 宁都县| 胶南市| 金山区| 唐山市| 浙江省| 桂东县| 滨海县| 开鲁县| 建水县| 两当县| 河北区| 河间市| 临安市| 景德镇市| 江西省| 通州市| 岱山县| 亳州市| 井冈山市| 兰州市| 渭南市| 山丹县| 涞水县|