chapter 16 網絡編程

 

套接字:通信端點
什麼是套接字?python

書上說的端口是數據結構和I/O緩存區」是指硬件端口,網絡編程裏的端口能夠理解爲應用程序的ID。編程

說得形象點,套接字就相似咱們人類的門
咱們打開門,經過門外面的人能夠進來
咱們推開門,裏面的人也能夠出去
一樣,外面的數據能夠經過socket把它存儲在本地機器的緩衝區裏等待本地機器接收
本地機器的數據能夠經過socket放在緩衝區裏等待發送到對方機器上
當咱們把門給關上時,就拒絕了和外面世界的交往。緩存


套接字是一種具備以前所說的「通信端點」概念的計算機網絡數據結構。網絡化的應用程序在開始任何通安全

訊以前都必須要建立套接字。就像電話的插口同樣,沒有它就徹底沒辦法通信。
套接字有兩種,分別是基於文件型的和基於網絡型的。
基於文件型的:
Unix 套接字是咱們要介紹的第一個套接字家族。其「家族名」爲AF_UNIX,因爲兩個進程都運行在同一臺服務器

機器上,並且這些套接字是基於文件的。因此,它們的底層結構是由文件系統來支持的。這樣作至關有道網絡

理,由於,同一臺電腦上,文件系統的確是不一樣的進程都能訪問的。數據結構

基於網絡型的
它有本身的家族名字:AF_INET,或叫「地址家族:Internet」。框架

Python 只支持AF_UNIX,AF_NETLINK,和AF_INET 家族。因爲咱們只關心網絡編程,因此在本章的大部分異步

時候,咱們都只用AF_INET。socket

套接字的類型只有兩種。一種是面向鏈接的套接字,即在通信以前必定要創建一條鏈接,就像跟朋友打電

話時那樣。這種通信方式也被稱爲「虛電路」或「流套接字」。面向鏈接的通信方式提供了順序的,可靠

的,不會重複的數據傳輸,並且也不會被加上數據邊界。這也意味着,每個要發送的信息,可能會被拆

分紅多份,每一份都會很少很多地正確到達目的地。而後被從新按順序拼裝起來,傳給正在等待的應用程

序。


建立套接字:
from socket import *

tcpsock=socket(AF_INET,SOCK_STREAM)
udpsock=socket(AF_INET,SOCK_DGRAM)


套接字對象(內建)方法

函數 描述
服務器端套接字函數
s.bind() 綁定地址(主機,端口號對)到套接字
s.listen() 開始TCP 監聽
s.accept() 被動接受TCP 客戶的鏈接,(阻塞式)等待鏈接的到來
客戶端套接字函數
s.connect() 主動初始化TCP 服務器鏈接
s.connect_ex() connect()函數的擴展版本,出錯時返回出錯碼,而不是拋異常
公共用途的套接字函數
s.recv() 接收TCP 數據
s.send() 發送TCP 數據
s.sendall() 完整發送TCP 數據
s.recvfrom() 接收UDP 數據
s.sendto() 發送UDP 數據
s.getpeername() 鏈接到當前套接字的遠端的地址
s.getsockname() 當前套接字的地址
s.getsockopt() 返回指定套接字的參數
s.setsockopt() 設置指定套接字的參數
s.close() 關閉套接字

Blocking-Oriented Socket Methods
s.setblocking() 設置套接字的阻塞與非阻塞模式
s.settimeout()       設置阻塞套接字操做的超時時間
s.gettimeout()    獲得阻塞套接字操做的超時時間
面向文件的套接字的函數
s.fileno() 套接字的文件描述符
s.makefile() 建立一個與該套接字關連的文件

 

 

 建立一個tcp服務器的僞代碼:
ss=socket()  #建立服務器套接字
ss.bind()    #把地址綁定到套接字上
ss.listen()  #監聽連接
inf_loop     #服務器無線循環
cs=ss.accept()    #接受客戶的連接
comm_loop           #通信循環
cs.recv()/cs.send()    #對話(接受與發送)
cs.close()           #關閉客戶套接字
ss.close()           #關閉服務器套接字(可選)


會建立一個TCP 服務器程序:

from socket import *
from time import ctime

HOST=''
PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)

tcpSerSock=socket(AF_INET,SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)


while True:
    print 'waiting for connection...'
    tcpCliSock,addr=tcpSerSock.accept()
    print '... connected from:',addr

    while True:
        data=tcpCliSock.rece(BUFSIZ)
        if not data:
            break
        tcpCliSock.send('[%s]%s'%(ctime(),data))

    tcpCliSock.close()
tcpSerSock.close()


建立TCP 客戶端:

僞代碼:
cs = socket() # 建立客戶套接字
cs.connect() # 嘗試鏈接服務器
comm_loop: # 通信循環
cs.send()/cs.recv() # 對話(發送/接收)
cs.close() # 關閉客戶套接字

實例:
from socket import *
from time import ctime,sleep

HOST='localhost'

PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)

tcpCliSock=socket(AF_INET,SOCK_STREAM)

tcpCliSock.connect(ADDR)

while True:
    data=raw_input('>')
    if not data:
        break

    tcpCliSock.send(data)
    sleep(6)
    data=tcpCliSock.recv(BUFSIZ)
    if not data:
        break
    print data
tcpCliSock.close()

運行咱們的客戶端與服務器程序,先運行服務器端再運行客戶端,由於服務器端是被動的,他要在那裏等

待着。

socket.error: [Errno 10054]說明服務器端出現了error,socket.error: [Errno 10053]客戶端出現了問


建立一個UDP 服務器:


ss = socket() # 建立一個服務器套接字
ss.bind() # 綁定服務器套接字
inf_loop: # 服務器無限循環
cs = ss.recvfrom()/ss.sendto() # 對話(接收與發送)
ss.close() # 關閉服務器套接字


實例:
from socket import *
from time import ctime,sleep

HOST='localhost'

PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)

tcpCliSock=socket(AF_INET,SOCK_STREAM)

tcpCliSock.connect(ADDR)

while True:
    data=raw_input('>')
    if not data:
        break

    tcpCliSock.send(data)
    sleep(6)
    data=tcpCliSock.recv(BUFSIZ)
    if not data:
        break
    print data
tcpCliSock.close()

建立一個UDP 客戶端:
僞代碼:
cs = socket() # 建立客戶套接字
comm_loop: # 通信循環
cs.sendto()/cs.recvfrom() # 對話(發送/接收)
cs.close() # 關閉客戶套接字

實例:
from socket import *

HOST='localhost'
PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)

udpCliSock=socket(AF_INET,SOCK_DGRAM)

while True:
    data=raw_input('>')
    if not data:
        break
    udpCliSock.sendto(data,ADDR)
    data,ADDR=udpCliSock.recvfrom(BUFSIZ)

    if not data:
        break

    print data
udpCliSock.close

套接字模塊屬性:
屬性名字 描述
數據屬性
AF_UNIX, AF_INET, AF_INET6a Python 支持的套接字家族
SO_STREAM, SO_DGRAM 套接字類型 (TCP = 流, UDP = 數據報)
has_ipv6b 表示是否支持IPv6 的標誌變量
異常
error 套接字相關錯誤
herrora 主機和地址相關的錯誤
gaierrora 地址相關的錯誤
timeoutb 超時
函數
socket() 用指定的地址家族,套接字類型和協議類型(可選)建立一個套接字對象
socketpair()c 用指定的地址家族,套接字類型和協議類型(可選)建立一對套接字對象
fromfd() 用一個已經打開的文件描述符建立一個套接字對象數據屬性
ssl()d 在套接字初始化一個安全套接字層(SSL)。不作證書驗證。
getaddrinfo()a 獲得地址信息
getfqdn()e 返回完整的域的名字
gethostname() 獲得當前主機名

gethostbyname() 由主機名獲得對應的ip 地址
gethostbyname_ex() gethostbyname()的擴展版本,返回主機名,主機全部的別名和
IP 地址列表。
gethostbyaddr() 由IP 地址獲得DNS 信息,返回一個相似gethostbyname_ex()
的3 元組。
getprotobyname() 由協議名(如'tcp')獲得對應的號碼。
getservbyname()/ 由服務名獲得對應的端口號或相反
getservbyport() 兩個函數中,協議名都是可選的。
ntohl()/ntohs() 把一個整數由網絡字節序轉爲主機字節序
htonl()/htons() 把一個整數由主機字節序轉爲網絡字節序
inet_aton()/ 把IP 地址轉爲32 位整型,以及反向函數。(僅對IPv4 地址有效)
inet_ntoa()
inet_pton()/ 把IP 地址轉爲二進制格式以及反向函數。(僅對IPv4 地址有效)
inet_ntop()b
getdefaulttimeout()/ 獲得/設置默認的套接字超時時間,單位秒(浮點數)
setdefaulttimeout()

 

*SocketServer 模塊

用*SocketServer 模塊簡化上面的例子:
tcp server:
from SocketServer import TCPServer as TCP, StreamRequestHandler as SRH
from time import ctime

HOST=''
PORT=21567
ADDR=(HOST,PORT)

class MyRequestHandler(SRH):
    def handle(self):
        print '...connected from:',self.client_address
        self.wfile.write('[%s]%s'%(ctime(),self.rfile.readline()))

tcpServ=TCP(ADDR,MyRequestHandler)
print 'waiting for connection...'
tcpServ.serve_forever()


tcp client:

from socket import *
from time import ctime,sleep

HOST='localhost'

 核心編程

PORT=21567
BUFSIZ=1024
ADDR=(HOST,PORT)

 

while True:
    tcpCliSock=socket(AF_INET,SOCK_STREAM)
    tcpCliSock.connect(ADDR)
    data=raw_input('>')
    if not data:
        break

    tcpCliSock.send('%s\r\n'%data)

    data=tcpCliSock.recv(BUFSIZ)
    if not data:
        break
    print data.strip()
    tcpCliSock.close()

Twisted 框架介紹:Twisted 是一個徹底事件驅動的網絡框架。它容許你使用和開發徹底異步的網絡應用程序和協議。這個模塊要單獨安裝,內容也比較多,稍後再仔細研究吧

相關文章
相關標籤/搜索