天天看點

Python3 網絡程式設計——SOCKET程式設計SOCKET程式設計

SOCKET程式設計

socket(套接字): 應用程式通常通過”套接字”向網絡送出請求或者應答網絡請求,使主機間或者一台計算機上的程序間可以通訊。網絡大多基于Socket通信。

通過IP+端口定位對方并發送消息的通信機制

分為UDP和TCP。

socket()函數

用 socket()函數來建立套接字,文法格式如下:

socket.socket([family[, type[, proto]]])

參數

family: 套接字家族可以使AF_UNIX或者AF_INET(ipv4協定族)

type: 套接字類型 。分為:面向連接配接的:SOCK_STREAM(使用TCP通信)和面向非連接配接:SOCK_DGRAM(使用UDP通信)

protocol: 一般不填預設為0.

Socket 對象(内建)方法

伺服器端套接字:

s.bind() :綁定位址(host,port)到套接字, 在AF_INET下,以元組(host,port)的形式表示位址。

s.listen() :TCP監聽。backlog指定在拒絕連接配接之前,作業系統可以挂起的最大連接配接數量。該值至少為1,大部分應用程式設為5。

s.accept() :被動接受TCP用戶端連接配接,(阻塞式)等待連接配接的到來。

用戶端套接字:

s.connect(): 主動初始化TCP伺服器連接配接。一般address的格式為元組(hostname,port)。

公共用途的套接字函數:

s.recv() :接收TCP資料,資料以字元串形式傳回,bufsize指定要接收的最大資料量。

s.send() :發送TCP資料,将string中的資料發送到連接配接的套接字。傳回值是要發送的位元組數量,該數量可能小于string的位元組大小。

s.recvfrom() :接收UDP資料,與recv()類似,但傳回值是(data,address)。其中data是包含接收資料的字元串,address是發送資料的套接字位址。

s.sendto(): 發送UDP資料,将資料發送到套接字,address是形式為(ipaddr,port)的元組,指定遠端位址。傳回值是發送的位元組數。

s.close() :關閉套接字。

UDP 程式設計

Server端流程 :

1. 建立socket,socket是負責具體通信的一個執行個體

2. 綁定,為建立的socket指派固定的端口和ip位址

3. 接受對方發送内容

4. 給對方發送回報,此步驟為非必須步驟。

Client端流程:

1. 建立通信的socket 。

2. 發送内容到指定伺服器 。

3. 接受伺服器給定的回報内容。

伺服器案例:

# socket子產品負責socket程式設計
import socket

# 模拟伺服器的函數
def serverFunc():
    # 1. 建立socket
    # socket.AF_INET:使用ipv4協定族
    # socket.SOCK_DGRAM: 使用UDP通信
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # 2. 綁定ip和port
    # 127.0.0.1: 這個ip位址代表的是機器本身
    # 9999: 随手指定的端口号
    # 位址是一個tuple類型,(ip, port)
    addr = ("127.0.0.1",  )
    sock.bind( addr )


    # 接受對方消息
    # recvfrom接受的傳回值是一個tuple,前一項表示資料,後一項表示位址
    # 參數的含義是緩沖區大小
    # rst = sock.recvfrom(500)
    data, addr = sock.recvfrom()

    print(data)

    # 發送過來的資料是bytes格式,必須通過解碼才能得到str格式内容
    # decode預設參數是utf8
    text = data.decode()
    print(text)

    # 給對方傳回的消息
    rsp = "歡迎通路"

    # 發送的資料需要編碼成bytes格式,預設是utf8
    data = rsp.encode()
    sock.sendto(data, addr)


if __name__ == '__main__':
    print("Starting server.........")
    serverFunc()
    print("Ending server........")
           

用戶端案例:

import socket

def clientFunc():

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    text = "Hello World!"
    data = text.encode()

    # 發送
    sock.sendto(data,  ("127.0.0.1", ))
    data, addr  = sock.recvfrom()
    data = data.decode()
    print(data)

if __name__ == '__main__':
    clientFunc()
           

伺服器程式要求永久運作,一般用死循環處理。

TCP程式設計

面向連結的傳輸,即每次傳輸之前需要先建立一個連結。

Server端的流程:

1.建立socket負責具體通信,這個socket其實隻負責接受對方的請求,真正通信的是連結後重建立立的socket。

2. 綁定端口和位址。

3. 監聽接入的通路socket。

4. 接受通路的socket,可以了解為建立了一個通訊的連結通路。

5. 接受對方的發送内容,利用接收到的socket接收内容。

6. 如果有必要,給對方發送回報資訊。

7. 關閉連結通路。

Client端流程:

1. 建立通信socket。

2. 連結對方,請求跟對方建立通路。

3. 發送内容到對方伺服器。

4. 接受對方的回報。

5. 關閉連結通路。

伺服器案例:

import socket

def  tcp_srv():
    # 1. 建立socket負責具體通信。
    # 需要用到兩個參數
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 2. 綁定端口和位址
    # 此位址資訊是一個元組類型内容,分兩部分:字元串(代表ip)+端口
    addr = ("127.0.0.1", )
    sock.bind(addr)

    # 3. 監聽接入的通路socket
    sock.listen()

    while True:
        # 4. 接受通路的socket,即建立一個通訊的連結通路
        # accept傳回的元組第一個元素指派給skt,第二個指派給addr
        skt,addr = sock.accept()

        # 5. 接受對方的發送内容
        # 500代表接收使用的buffersize
        msg = skt.recv()
        msg = msg.decode()
        rst = "Received msg: {0} from {1}".format(msg, addr)
        print(rst)
        # 6. 如果有必要,給對方發送回報資訊
        skt.send(rst.encode())

        # 7. 關閉連結通路
        skt.close()

if __name__ == "__main__":
    print("Starting tcp server.......")
    tcp_srv()
    print("Ending tcp server.......")
           

用戶端案例:

import socket

def tcp_clt():
    # 1. 建立通信socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 連結對方,請求跟對方建立通路
    addr = ("127.0.0.1", )
    sock.connect(addr)
    # 3. 發送内容到對方伺服器
    msg = "Hello World!"
    sock.send(msg.encode())
    # 4. 接受對方的回報
    rst =  sock.recv()
    print(rst.decode())
    # 5. 關閉連結通路
    sock.close()


if __name__ == "__main__":
    tcp_clt()