python-socket編程(二)模塊基礎

一、socket模塊

1.1 創建套接字對象

socket.socket([family[, type]])
  • family: 套接字家族可以使用AF_UNIX或者AF_INET
  • type: 套接字類型可以根據是面向連接的還是非連接分爲SOCK_STREAM或SOCK_DGRAM

1.2 重用套接字

解決有時候地址被佔用的問題

s.setsockopt(SQL_SOCKET,SO_REUSEADDR,1)

1.3 套接字對象內建方法

1.3.1 服務端

  • s.bind():綁定地址(host,port)到套接字, 在AF_INET下,以元組(host,port)的形式表示地址。
  • s.listen(backlog=n):開始TCP監聽。backlog指定在拒絕連接之前,操作系統可以掛起的最大連接數量。該值至少爲1,大部分應用程序設爲5就可以了
  • s.accept():被動接受TCP客戶端連接,(阻塞式)等待連接的到來

1.3.2 客戶端

  • s.connect():主動初始化TCP服務器連接,。一般address的格式爲元組(hostname,port),如果連接出錯,返回socket.error錯誤
  • s.connect_ex():connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常

公共使用

  • s.recv():接收TCP數據,數據以字符串形式返回,bufsize指定要接收的最大數據量。flag提供有關消息的其他信息,通常可以忽略
  • s.send():發送TCP數據,將string中的數據發送到連接的套接字。返回值是要發送的字節數量,該數量可能小於string的字節大小
  • s.sendall():完整發送TCP數據,完整發送TCP數據。將string中的數據發送到連接的套接字,但在返回之前會嘗試發送所有數據。成功返回None,失敗則拋出異常
  • s.recvfrom():接收UDP數據,與recv()類似,但返回值是(data,address)。其中data是包含接收數據的字符串,address是發送數據的套接字地址
  • s.sendto():發送UDP數據,將數據發送到套接字,address是形式爲(ipaddr,port)的元組,指定遠程地址。返回值是發送的字節數
  • s.close():關閉套接字
  • s.getpeername():返回連接套接字的遠程地址。返回值通常是元組(ipaddr,port)
  • s.getsockname():返回套接字自己的地址。通常是一個元組(ipaddr,port)
  • s.setsockopt(level,optname,value):設置給定套接字選項的值。
  • s.getsockopt(level,optname[.buflen]):返回套接字選項的值。
  • s.settimeout(timeout):設置套接字操作的超時期,timeout是一個浮點數,單位是秒。值爲None表示沒有超時期。一般,超時期應該在剛創建套接字時設置,因爲它們可能用於連接的操作(如connect())
  • s.gettimeout():返回當前超時期的值,單位是秒,如果沒有設置超時期,則返回None
  • s.fileno():返回套接字的文件描述符
  • s.setblocking(flag):如果flag爲0,則將套接字設爲非阻塞模式,否則將套接字設爲阻塞模式(默認值)。非阻塞模式下,如果調用recv()沒有發現任何數據,或send()調用無法立即發送數據,那麼將引起socket.error異常
  • s.makefile():創建一個與該套接字相關連的文件

二、tcp簡單實例

一對一模型

  • 服務端
import socket

ip_port=('127.0.0.1',8001)
backlog=5
buffersize=1024

tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(backlog)

conn,addr = tcp_server.accept()
print(conn)
#<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8001), raddr=('127.0.0.1', 57902)>
print(addr)
('127.0.0.1', 57902)
msg = conn.recv(buffersize).decode('utf-8')
print("客戶端發來的消息是:%s"%msg)
conn.close()
tcp_server.close()
  • 客戶端
import socket

ip_port = ('127.0.0.1',8001)

tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_client.connect(('127.0.0.1',8001))

msg = "你好,我是客戶端"
tcp_client.send(msg.encode('utf-8'))

tcp_client.clsoe()

tcp連接的時候要簡要說明,無論是客戶端還是服務端,當發送消息的時候都會通過socket發送至對方主機的內存中的緩存區域(內核態內存),也就是buffer區域。例子中buffer設置爲1024bytes,若發送的量大於這個數值,那當程序收取的時候最後還是隻能收取1024bytes。

一對多模型

  • 服務端
import socket

ip_port=('127.0.0.1',8001)
backlog=5
buffersize=1024


tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(backlog)
while True:
    conn,addr = tcp_server.accept()
    while True:
        msg = conn.recv(buffersize).decode('utf-8')
        if not msg:
            break
        # 當客戶端斷開連接的時候會一直循環收到空信息,因此使用此條退出循環
        print("客戶端發來的消息是:%s"%msg
    conn.close()
    #當一個客戶端斷開連接,服務端也斷開此次連接,循環進行下一次accept等待連接
tcp_server.close()
  • 客戶端
import socket

ip_port = ('127.0.0.1',8001)

tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_client.connect(('127.0.0.1',8001))
while True:
    msg = input('-->:')
    if not msg:continue
    # 如果輸入的信息爲空則跳過此次發送
    tcp_client.send(msg.encode('utf-8'))
tcp_client.close()
  • 我們用客戶端的代碼同時開啓兩個客戶端
  • 客戶端1發送兩條信息(1)hello (2)i am 1
  • 客戶端2發送兩條信息(1)hello (2)i am 2
  • 服務端會收到兩條消息 “hello”和“ i am 1”
  • 斷開客戶端1
  • 服務端會收到一條消息 “helloi am 2”,這是因爲服務端首先會將發客戶端2的連接在backlog連接池掛起,客戶端發送的消息會儲存在連接池,服務器段一次收取一條,而tcp是數據流,所以客戶端2發送的兩條信息會粘連在一起,此爲粘包現象。這個現象我們會在後續深入討論。

三、UDP簡單實例

  • 服務端
import socket

ip_port=('127.0.0.1',8001)
backlog=5
buffersize=1024

udp_server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
udp_server.bind(ip_port)
while True:
    data,addr = udp_server.recvfrom(buffersize)
    print("udp客戶端發來的消息是:%s"%data.decode('utf-8'))
  • 客戶端
import socket

ip_port = ('127.0.0.1',8001)

udp_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

while True:
    data = input("客戶請輸入數據:")
    udp_client.sendto(data.encode('utf-8'),ip_port)

使用tcp傳輸數據的時候,發送空數據會導致進程堵塞,而udp不會產生的這個問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章