初識socket

来源:https://www.cnblogs.com/caesar-id/archive/2019/12/17/12057502.html
-Advertisement-
Play Games

一、初識socket socket(套接字)起源於20世紀70年代加利福尼亞大學伯克利分校版本的Unix,即人們所說的BSDUnix。因此,有時人們也把套接字稱為“伯克利套接字”或“BSD套接字”。一開始,套接字被設計用在同一臺主機上多個應用程式之間的通訊。這也被稱進程間通訊,或IPC。socket ...


一、初識socket

       socket(套接字)起源於20世紀70年代加利福尼亞大學伯克利分校版本的Unix,即人們所說的BSDUnix。因此,有時人們也把套接字稱為“伯克利套接字”或“BSD套接字”。一開始,套接字被設計用在同一臺主機上多個應用程式之間的通訊。這也被稱進程間通訊,或IPC。socket(套接字)也可用在相同或者不同的設備進程之間進行通信。

       套接字(socket)是一個抽象層,應用程式可以通過它發送或接收數據,可對其進行像對文件一樣的打開、讀寫和關閉等操作。套接字允許應用程式將I/O插入到網路中,並與網路中的其他應用程式進行通信。網路套接字是IP地址與埠的組合。

       為了滿足不同的通信程式對通信質量和性能的要求,一般的網路系統提供了三種不同類型的套接字,以供用戶在設計網路應用程式時根據不同的要求來選擇。這三種套接為流式套接字(SOCK-STREAM)、數據報套接字(SOCK-DGRAM)和原始套接字(SOCK-RAW)。

流式套接字:它提供了一種可靠的、面向連接的雙向數據傳輸服務,實現了數據無差錯、無重覆的發送。流式套接字內設流量控制,被傳輸的數據看作是無記錄邊界的位元組流。在TCP/IP協議簇中,使用TCP協議來實現位元組流的傳輸,當用戶想要發送大批量的數據或者對數據傳輸有較高的要求時,可以使用流式套接字。

數據報套接字:它提供了一種無連接、不可靠的雙向數據傳輸服務。數據包以獨立的形式被髮送,並且保留了記錄邊界,不提供可靠性保證。數據在傳輸過程中可能會丟失或重覆,並且不能保證在接收端按發送順序接收數據。在TCP/IP協議簇中,使用UDP協議來實現數據報套接字。在出現差錯的可能性較小或允許部分傳輸出錯的應用場合,可以使用數據報套接字進行數據傳輸,這樣通信的效率較高。

原始套接字:該套接字允許對較低層協議(如IP或ICMP)進行直接訪問,常用於網路協議分析,檢驗新的網路協議實現,也可用於測試新配置或安裝的網路設備。
軟體開發架構一般分為C/S和B/S兩種。

  • C/S:Client與Server ,中文意思:客戶端與伺服器端架構
  • B/S:Browser與Server,中文意思:瀏覽器端與伺服器端架構

二、socket.socket()模塊簡介

socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
初始化參數:
family:套接字有很多家族,AF_INET,AF_UNIX ,AF_IRDA,等多種,我們先學習AF_INET,預設是AF_INET。
AF_UNIX:是基於文件類型的套接字家族,unix一切皆文件,基於文件的套接字調用的就是底層的文件系統來取數據,兩個套接字進程運行在同一機器,可以通過訪問同一個文件系統間接完成通信。
AF_INET:是基於網路類型的套接字家族(還有AF_INET6被用於ipv6,AF_INET是使用最廣泛的一個,python支持很多種地址家族,但是由於我們只關心網路編程,所以大部分時候我們只使用AF_INET)
type:套接字類型有如下幾種:預設是SOCK_STREAM。

  • SOCK_STREAM:TCP流(常用)
  • SOCK_DGRAM¶:UDP數據報(常用)
  • SOCK_RAW:原始套接字(常用)
  • SOCK_RDM:保證交付數據報但不保證順序。
  • SOCK_SEQPACKET:可靠的連續數據包服務

proto:埠號通常為0,這樣socket會隨機使用一個沒被占用的埠,在能確定埠沒被占用的情況下可以手動指定埠號,在地址家族為AF_CAN的情況下,協議應該是CAN_RAW、CAN_BCM或CAN_ISOTP之一。
fileno:從指定的文件描述符中自動檢測family,type和proto的值。預設是None。

三、socket object常用方法:

socket.bind(address):將socket綁定一個地址,這個socket必須沒有綁定過。

socket.listen([backlog]):socket伺服器進入監聽模式以接受連接。如果指定了backlog這個值最少為0。backlog代表沒有被 accept 取走的連接數量。如果未指定,系統會選擇預設的合理值。

socket.accept():接受一個連接。socket必須綁定到一個地址並監聽連接。返回值是一個元組(conn,address),其中conn是一個新的套接字對象,用於在連接上發送和接收數據,address是綁定到連接另一端套接字的地址。

socket.recv(bufsize):接收發送過來的數據。 返回值是一個位元組對象,一次接收的最大數據量由bufsize指定。為了與硬體和網路實際情況保持最佳匹配,bufsize的值應為2的次冪,例如1024,2047,4096等。

socket.recvfrom(bufsize):接收數據。返回值是一個元組(位元組,地址),其中位元組是一個位元組對象,表示接收到的數據,地址是發送數據的socket的地址。

socket.recvmsg(bufsize,ancbufsize,):從套接字接收數據和輔助數據。bufsize(位元組)接收數據的大小ancbufsize參數設置用於接收輔助數據的內部緩衝區的大小(以位元組為單位)。它預設為0,表示將不會接收任何輔助數據。可以使用CMSG_SPACE()或CMSG_LEN()計算輔助數據的適當緩衝區大小,不適合緩衝區的項目可能會被截斷或丟棄。返回值是一個四元組:(數據,ancdata,msg_flags,address)。數據項是一個位元組對象,ancdata項是零個或多個元組(cmsg_level,cmsg_type,cmsg_data)的列表,表示接收到的輔助數據(控制消息):cmsg_level和cmsg_type是分別指定協議級別和協議特定類型的整數,而cmsg_data是位元組對象保存相關數據。 msg_flags項是指示接收消息條件的各種標誌的按位或;有關詳細信息,請參見系統文檔。如果接收套接字未連接,則address是發送套接字的地址(如果有);否則,其值未指定。

socket.send(bytes):將數據發送到socket。該socket必須連接到遠程socket。返回發送的位元組數。

socket.sendall(bytes):與send()類似不同的是此方法繼續從位元組發送數據,直到所有數據都已發送或發生錯誤為止。 成功不返回任何內容。 如果出錯,則會引發異常,所以無法確定成功發送了多少數據。

socket.sendto(bytes,address):將數據發送到socket。不應連接到遠程socket,因為目標socket是按地址指定的。返回發送的位元組數。

socket.connect(address):根據地址連接遠程socket。

socket.fileno():返回socket的文件描述符(一個小整數),如果失敗則返回-1。這對於select.select()非常有用。在Windows下,這個方法返回的小整數不能用於可以使用文件描述符的地方(例如os.fdopen())。Unix沒有這個限制。

socket.getpeername():返回socket連接到的遠程地址,埠號。在某些系統上,可能不支持此功能。

socket.getsockname():返回自己socket的地址和埠號。

socket.getblocking():如果套接字處於阻塞模式,則返回True;如果處於非阻塞模式,則返回False。適用於Python3.7。

socket.shutdown(how):關閉連接。如果how=SHUT_RD則不允許接收數據。如果how=SHUT_WR則不允許發送數據。如果how=SHUT_RDWR如何,則不允許發送和接收。

socket.close():釋放與連接關聯的資源,但不一定立即關閉連接,套接字對象上的所有後續操作都將失敗。遠程端將不再接收任何數據。如果希望及時關閉連接,在close()之前調用shutdown()。

socket.detach():關閉socket對象而不,而不實際關閉底層文件描述符。返迴文件描述符,此調用後無法使用socket對象,但可以使用文件描述符,用於其他目的。

 

socket.settimeout(value):設置socket阻塞模式下超時時間。value值是非負數(單位:秒),如果給出了value,在value秒後還沒有接收到數據,連接請求,將引發超時異常。如果給定0,則套接字將處於非阻塞模式。如果是None,套接字將進入阻塞模式。

參考文檔: https://docs.python.org/3/library/socket.html?highlight=socket#socket.AF_INET。

 

四、簡單示例

建立基本的連接

server端:

import socket
server_obj = socket.socket()              # 創建socket對象
server_obj.bind(("socket伺服器地址",9000))  # socket綁定IP地址和監聽埠
server_obj.listen(5)                      # 監聽遠程socket連接
con,addr = server_obj.accept()            # 建立socket連接
msg = con.recv(1024).decode("utf-8")      # 接收遠程socket發來的數據
print(msg)
con.send(msg.upper().encode("utf-8"))     # 發送數據給遠程socket
con.close()         # 關閉連接
server_obj.close()  # 關閉連接

client端:

import socket
client = socket.socket()                # 創建socket對象
client.connect(("遠程socket地址",9000))  # 連接遠程socket
msg = input(">>>")
client.send(msg.encode("utf-8"))             # 發送數據給遠程socket
recv_msg = client.recv(1024).decode("utf-8") # 接收遠程socket發來的數據
print(recv_msg)
client.close()  # 關閉socket

上面的示例只能收一次,發一次消息,然後就結束了。下麵我們使用while迴圈,來迴圈收,發消息。

server端:

import socket
server_obj = socket.socket()              # 創建socket對象
server_obj.bind(("192.168.10.102",9000))  # socket綁定地址和埠
server_obj.listen(5)                      # 監聽socket連接請求
con,addr = server_obj.accept()            # 建立socket連接
print('遠端socket對象:',con.getpeername()) # 列印遠程socket信息
while True:
    try:
        msg = con.recv(1024)  # 接收遠程socket發來的數據
        if msg.decode('utf-8').upper()=='Q':break # 如果發來的是q表示斷開連接
        print(msg.decode("utf-8"))
        con.send('我接到了你發來的消息'.encode('utf-8'))
    except Exception:
        break
print(連接已斷開)
con.close()
server_obj.close()

client端:

import socket
client = socket.socket()                # 創建socket對象
client.connect(("192.168.10.102",9000)) # 連接遠程socket
while True:
    msg = input(">>>")
    if msg.upper() == 'Q':break       # 輸入q退出程式
    client.send(msg.encode("utf-8"))  # 發送數據給遠程socket
    recv_msg = client.recv(1024).decode("utf-8") # 接收遠程socket發來的數據
    print(recv_msg)
print('退出程式')
client.close()

此時我們的伺服器只能接受一個客戶端的連接,如果客戶端斷開了,服務端將關閉。如果想讓伺服器一直接受請求一個客戶端斷開連接後,繼續接受下一個客戶端的連接,看如下server代碼:

import socket
server_obj = socket.socket()              # 創建socket對象
server_obj.bind(("192.168.10.102",9000))  # socket綁定地址和埠
server_obj.listen(5)                      # 監聽socket連接請求
while 1:
    print('等待接收遠程socket連接......')
    con,addr = server_obj.accept()        # 建立socket連接
    print('連接一臺遠程socket:',con.getpeername())
    while True:
        try:
            msg = con.recv(1024)          # 接收遠程socke
            if msg.decode('utf-8').upper()=='Q':break
            print(msg.decode("utf-8"))
            con.send('我接到了你發來的消息'.encode('utf-8'))
        except Exception:
            break
    con_address,con_port = con.getpeername() # 獲取斷開socke對象信息
    print(con_address,'斷開了連接')
    con.close()
server_obj.close()

關於recv要註意的地方:

當緩衝區沒有數據可取時,recv會一直處於阻塞狀態,直到緩衝區至少有一個位元組數據可取,或者遠程端關閉。關閉遠程端並讀取所有數據後,返回空字元串。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • JavaScript 錯誤 - Throw 和 Try to Catch try 語句使您能夠測試代碼塊中的錯誤。 catch 語句允許您處理錯誤。 throw 語句允許您創建自定義錯誤。 finally 使您能夠執行代碼,在 try 和 catch 之後,無論結果如何。 錯誤總會發生! 當執行 J ...
  • 本書內容 本書從書名就可以看出來,講了架構的兩個東西,一個是原理,一個是案例。 案例部分沒有在導圖中體現,不過建議讀者還是要看一下案例,能夠通過案例對原理有更加深刻的印象 推薦程度 4.5 顆星 推薦原因 通讀本書,能對大型網站有更加直觀的感受 細節之處,能夠指導你設計網站架構選用的具體方案 即使以 ...
  • 在k8s里,你可以通過服務名去訪問相同namespace里的服務,然後服務可以解析到對應的pod,從而再由pod轉到對應的容器里,我們可以認為這個過程有兩個port的概念,service port 就是服務的port,在k8s配置文件里用 表示,還有一個是pod和容器的port,用targetPor ...
  • PHP 7.4.0 發佈了,此版本標志著 PHP 7 系列的第四次特性更新。 看了英文手冊後,發現其進行了許多改進,並帶來了一些新特性,現在將這些新特性您: 1.Typed Properties 類型屬性 類屬性現在支持類型聲明,以下示例將強制 $User-> id 只能分配 int 值,而 $Us ...
  • 首先介紹一下Java的各個層級,先放一張圖: 硬體,操作系統和操作系統介面:這三級不說大家都知道,操作系統有很多種,比如Windows,Linux。Windows又分為win7,win10,win xp等等;Linux有Ubuntu,CentOS;操作系統介面就是系統為開發者預留的,方便調用從而控制 ...
  • 之前的aop是通過手動創建代理類來進行通知的,但是在日常開發中,我們並不願意在代碼中硬編碼這些代理類,我們更願意使用DI和IOC來管理aop代理類。Spring為我們提供了以下方式來使用aop框架 一、以聲明的方式配置AOP(就是使用xml配置文件) 1.使用ProxyFactoryBean的方式: ...
  • tcp傳輸的數據是以流的形式傳輸的,因此就沒有辦法判斷到哪裡結束算是自己的一個消息,這樣就會出現粘包問題,多個包粘在一起了 可以使用這樣一個自定義的形式來解決,一個消息分為 head+body head包括數據的長度和數據編號 , 長度和編號都是uint32類型 也就是32位 占有4個位元組 , 總共 ...
  • Shiro是一個功能強大且易於使用的Java安全框架,主要功能有身份驗證、授權、加密和會話管理。 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...