如何正確理解套接字


一、認識套接字

TCP用主機的IP地址加上主機上的端口號作為TCP連接的端點,這種端點就叫做套接字(socket)或插口。
套接字用(IP地址:端口號)表示。

它是網絡通信過程中端點的抽象表示,包含進行網絡通信必需的五種信息:連接使用的協議,本地主機的IP地址,本地進程的協議端口,遠地主機的IP地址,遠地進程的協議端口。

 

套接字(socket)是一種通信機制,憑借這種機制,客戶/服務器系統的開發工作既可以在本地單機上進行,也可以跨網絡進行,Linux所提供的功能(如打印服 務,ftp等)通常都是通過套接字來進行通信的,套接字的創建和使用與管道是有區別的,因為套接字明確地將客戶和服務器區分出來,套接字可以實現將多個客 戶連接到一個服務器。

但是說了半天,還是理解不了什么是套接字,其實這是一個狗屎一樣的翻譯問題:

谷歌翻譯中socket直譯為插座,字典中關於socket的解釋為:an electrical device receiving a plug or light bulb to make a connection。譯為:接收插頭或燈泡以進行連接的電氣設備。用c/s模型圖來更好的理解插座的意義:

服務器就像一個大插排,包含很多插座,客戶端就是像一個插頭,每一個線程代表一條電線,客戶端將電線的插頭插到服務器插排上對應的插座上,就可以開始通信了。

 

數據傳輸需要通過協議,而套接字就是給數據傳輸添加協議的。

 

二、套接字特性

1、套接字屬性

套接字的特性由3個屬性確定,他們是,域,類型和協議

域指定套接字通信中使用的網絡介質,最常見的套接字域是AF_INET,它指的是Internet網絡

2、套接字類型

一個套接字可能有多種不同的通信方式

流套接字,流套接字提供一個有序,可靠,雙向節流的鏈接,流套接字由類型SOCK_STREAM指定,它是在AF_INET域中通過TCP/IP鏈接實現的,這就是套接字類型(其實就是通信方式)

與流套接字相反,由類型SOCK_DGRAM指定的數據報套接字不建立和維持一個連接,它對可以發送的數據長度有限制,數據報作為一個單獨的網絡消息被傳輸,它可能會丟失,復制或亂序

3、套接字協議

套接字協議,通常使用默認就可以了(也就是最后一個參數填0)

 

 

三、基於套接字的TCP網絡編程

1、創建流程概述

  • socket創建一個套接字,SOCK_DGRAM是用在UDP上的,而SOCK_STREAM是用於TCP協議的。
  • bind綁定IP和port
  • listen使套接字變為可以被動鏈接
  • accept等待客戶端的鏈接
  • close關閉資源

 

2、socket模塊常用於TCP的方法

  • connect(address):連接遠程計算機
  • send():發送數據
  • recv():接收數據
  • listen:開始監聽,等待客戶端連接

 

客戶端實例:

  1.  
    from socket import *
  2.  
    #建立套接字,第二個參數是流式套接字 tcp專用
  3.  
    clientd_socket = socket(AF_INET,SOCK_STREAM)
  4.  
    #目標主機,也就是服務器的ip和端口
  5.  
    serverAddress = ( '10.10.16.194',9999)
  6.  
    #主動和服務器發起鏈接
  7.  
    clientd_socket.connect(serverAddress)
  8.  
     
  9.  
    data = input( '請輸入數據')
  10.  
    #發送數據
  11.  
    clientd_socket.send(data.encode( 'utf-8'))
  12.  
    #接受數據
  13.  
    re = clientd_socket.recv( 128)
  14.  
    print(re.decode( 'utf-8'))
  15.  
     
  16.  
    clientd_socket.close()
  • accept():響應客戶端的請求

阻塞當前線程

如果沒有計算機連接,一直等待

如果有計算機連接,響應客戶端

 

服務端實例:

  1.  
    from socket import *
  2.  
    server_socket = socket(AF_INET,SOCK_STREAM)
  3.  
     
  4.  
    local_address = ( '10.10.16.194',9999)
  5.  
    #綁定本機ip和端口,那么此程序就只接收此端口好的所有網絡鏈接
  6.  
    server_socket.bind(local_address)
  7.  
     
  8.  
    #限制接受5個客戶端的數據
  9.  
    server_socket.listen( 5)
  10.  
    #接受鏈接,如果沒有鏈接那么處於阻塞狀態。
  11.  
    #有鏈接的時候,accept會返回兩個值,第一個是socket鏈接,第二個是遠程地址
  12.  
    lianjie,remoteAddress = server_socket.accept()
  13.  
    re = lianjie.recv( 128)
  14.  
    print(re.decode( 'utf-8'))
  15.  
    #發送數據
  16.  
    data = input( '請輸入發送內容')
  17.  
    lianjie.send(data.encode( 'utf-8'))
  18.  
     
  19.  
    lianjie.close() #server_socket中的其中一個鏈接
  20.  
    server_socket.close() #server_socket相當於一個大的容器

 

先運行服務端,在運行客戶端:結果

客戶端:

服務端:

 

3、改進一下,讓程序不會在一收一發后停止

客戶端:

  1.  
     
  2.  
    from socket import *
  3.  
    clientd_socket = socket(AF_INET,SOCK_STREAM)
  4.  
    serverAddress = ( '10.10.16.194',9999)
  5.  
    clientd_socket.connect(serverAddress)
  6.  
    while True:
  7.  
    data = input( '請輸入數據')
  8.  
    clientd_socket.send(data.encode( 'utf-8'))
  9.  
    re = clientd_socket.recv( 128)
  10.  
    print(re.decode( 'utf-8'))

服務端:

  1.  
    from socket import *
  2.  
    server_socket = socket(AF_INET,SOCK_STREAM)
  3.  
    local_address = ( '10.10.16.194',9999)
  4.  
    server_socket.bind(local_address)
  5.  
    server_socket.listen( 5)
  6.  
    lianjie,remoteAddress = server_socket.accept()
  7.  
    while True:
  8.  
    re = lianjie.recv( 128)
  9.  
    print(re.decode( 'utf-8'))
  10.  
    data = input( '請輸入發送內容')
  11.  
    lianjie.send(data.encode( 'utf-8'))
  12.  
    lianjie.close()
  13.  
    server_socket.close()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM