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()