Python學習之網絡編程

Python學習目錄python

  1. 在Mac下使用Python3
  2. Python學習之數據類型
  3. Python學習之函數
  4. Python學習之高級特性
  5. Python學習之函數式編程
  6. Python學習之模塊
  7. Python學習之面向對象編程
  8. Python學習之面向對象高級編程
  9. Python學習之錯誤調試和測試
  10. Python學習之IO編程
  11. Python學習之進程和線程
  12. Python學習之正則
  13. Python學習之經常使用模塊
  14. Python學習之網絡編程

互聯網的實現,分紅好幾層。每一層都有本身的功能,就像建築物同樣,每一層都靠下一層支持。如何分層有不一樣的模型,有的模型分七層,有的分四層。我以爲,把互聯網分紅五層,比較容易解釋。最底下的一層叫作"實體層"(Physical Layer),最上面的一層叫作"應用層"(Application Layer),中間的三層(自下而上)分別是"連接層"(Link Layer)、"網絡層"(Network Layer)和"傳輸層"(Transport Layer)。越下面的層,越靠近硬件;越上面的層,越靠近用戶。編程

網絡編程

TCP編程

Socket是網絡編程的一個抽象概念。一般咱們用一個Socket表示「打開了一個網絡連接」,而打開一個Socket須要知道目標計算機的IP地址和端口號,再指定協議類型便可。服務器

客戶端

建立Socket

# 導入socket庫:
import socket

# 建立一個socket:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 創建鏈接:
s.connect(('www.sina.com.cn', 80))
複製代碼

建立Socket時,AF_INET指定使用IPv4協議,若是要用更先進的IPv6,就指定爲AF_INET6SOCK_STREAM指定使用面向流的TCP協議,這樣,一個Socket對象就建立成功,可是尚未創建鏈接。網絡

鏈接服務器

s.connect(('www.sina.com.cn', 80))
複製代碼

注意參數是一個tuple,包含地址和端口號。多線程

發送請求

# 發送數據:
s.send(b'GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')
複製代碼

TCP鏈接建立的是雙向通道,雙方均可以同時給對方發數據。可是誰先發誰後發,怎麼協調,要根據具體的協議來決定。例如,HTTP協議規定客戶端必須先發請求給服務器,服務器收到後才發數據給客戶端。app

接收數據

# 接收數據:
buffer = []
while True:
    # 每次最多接收1k字節:
    d = s.recv(1024)
    if d:
        buffer.append(d)
    else:
        break
data = b''.join(buffer)
複製代碼

關閉Socket

# 接收數據:
buffer = []
while True:
    # 每次最多接收1k字節:
    d = s.recv(1024)
    if d:
        buffer.append(d)
    else:
        break
data = b''.join(buffer)
複製代碼

服務器

建立Socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
複製代碼

建立一個基於IPv4和TCP協議的Socket。socket

綁定監聽的地址和端口

# 監聽端口:
s.bind(('127.0.0.1', 9999))
s.listen(5)
print('Waiting for connection...')
複製代碼

listen()方法傳入的參數指定等待鏈接的最大數量。tcp

接受客戶端鏈接

while True:
    # 接受一個新鏈接:
    sock, addr = s.accept()
    # 建立新線程來處理TCP鏈接:
    t = threading.Thread(target=tcplink, args=(sock, addr))
    t.start()
複製代碼

每一個鏈接都必須建立新線程(或進程)來處理,不然,單線程在處理鏈接的過程當中,沒法接受其餘客戶端的鏈接:函數式編程

def tcplink(sock, addr):
    print('Accept new connection from %s:%s...' % addr)
    sock.send(b'Welcome!')
    while True:
        data = sock.recv(1024)
        time.sleep(1)
        if not data or data.decode('utf-8') == 'exit':
            break
        sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
    sock.close()
    print('Connection from %s:%s closed.' % addr)
複製代碼

UDP編程

TCP是創建可靠鏈接,而且通訊雙方均可以以流的形式發送數據。相對TCP,UDP則是面向無鏈接的協議。函數

使用UDP協議時,不須要創建鏈接,只須要知道對方的IP地址和端口號,就能夠直接發數據包。可是,能不能到達就不知道了。

雖然用UDP傳輸數據不可靠,但它的優勢是和TCP比,速度快,對於不要求可靠到達的數據,就能夠使用UDP協議。

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 綁定端口:
s.bind(('127.0.0.1', 9999))
複製代碼

建立Socket時,SOCK_DGRAM指定了這個Socket的類型是UDP。綁定端口和TCP同樣,可是不須要調用listen()方法,而是直接接收來自任何客戶端的數據:

print('Bind UDP on 9999...')
while True:
    # 接收數據:
    data, addr = s.recvfrom(1024)
    print('Received from %s:%s.' % addr)
    s.sendto(b'Hello, %s!' % data, addr)
複製代碼

recvfrom()方法返回數據和客戶端的地址與端口,這樣,服務器收到數據後,直接調用sendto()就能夠把數據用UDP發給客戶端。

注意這裏省掉了多線程,由於這個例子很簡單。

客戶端使用UDP時,首先仍然建立基於UDP的Socket,而後,不須要調用connect(),直接經過sendto()給服務器發數據:

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in [b'Michael', b'Tracy', b'Sarah']:
    # 發送數據:
    s.sendto(data, ('127.0.0.1', 9999))
    # 接收數據:
    print(s.recv(1024).decode('utf-8'))
s.close()
複製代碼

從服務器接收數據仍然調用recv()方法。

相關文章
相關標籤/搜索