網(wǎng)絡編程之Socket
我們已經(jīng)知道,假設我現(xiàn)在要寫一個程序,給另一臺計算機發(fā)數(shù)據(jù),必須通過tcp/ip協(xié)議
,但具體的實現(xiàn)過程是什么呢?我應該怎么操作才能把數(shù)據(jù)封裝成tcp/ip的包,又執(zhí)行什么指令才能把數(shù)據(jù)發(fā)到對端機器上呢?
不能只有世界觀,沒有方法論呀。。。此時,socket隆重登場,簡而言之,socket這個東東干的事情,就是幫你把tcp/ip協(xié)議層的各種數(shù)據(jù)封裝啦、數(shù)據(jù)發(fā)送、接收等通過代碼已經(jīng)給你封裝好了,你只需要調(diào)用幾行代碼,就可以給別的機器發(fā)消息了。
一、Socket介紹
1、什么是Socket
Socket是應用層與TCP/IP協(xié)議族通信的中間軟件抽象層。它是一組接口
。在設計模式中,Socket其實就是一個門面模式,它把復雜的TCP/IP協(xié)議族隱藏在Socket接口后面,對用戶來說,一組簡單的接口就是全部。
socket起源于Unix,而Unix/Linux基本哲學之一就是“一切皆文件”,都可以用“打開open –> 讀寫write/read –>
關閉close”模式
來操作。Socket就是該模式的一個實現(xiàn),socket即是一種特殊的文件,一些socket函數(shù)就是對其進行的操作(讀/寫IO、打開、關閉)。
你想給另一臺計算機發(fā)消息,你知道他的IP地址,他的機器上同時運行著qq、迅雷、word、瀏覽器等程序,你想給他的qq發(fā)消息,那想一下,你現(xiàn)在只能通過ip找到他的機器,但如果讓這臺機器知道把消息發(fā)給qq程序呢?答案就是通過port,一個機器上可以有0-65535個端口,你的程序想從網(wǎng)絡上收發(fā)數(shù)據(jù),就必須綁定一個端口,這樣,遠程發(fā)到這個端口上的數(shù)據(jù),就全會轉給這個程序。
2、Socket通信套路
當通過socket建立起2臺機器的連接后,本質(zhì)上socket只干2件事,一是收數(shù)據(jù),一是發(fā)數(shù)據(jù),沒數(shù)據(jù)時就等著。
socket 建立連接的過程跟我們現(xiàn)實中打電話比較像,打電話必須是打電話方和接電話方共同完成的事情,我們分別看看他們是怎么建立起通話的。
接電話方:
1.首先你得有個電話 2.你的電話要有號碼 3.你的電話必須連上電話線 4.開始在家等電話 5.電話鈴響了,接起電話,聽到對方的聲音
打電話方:
1.首先你得有個電話 2.輸入你想撥打的電話 3.等待對方接聽 4.say “hi 約么,我有七天酒店的打折卡噢~”
5.等待回應——》響應回應——》等待回應。。。。
把上述事件翻譯成socket通信
接電話方(socket服務器端):
1.首先你得有個電話\(生成socket對象\) 2.你的電話要有號碼\(綁定本機ip+port\) 3.你的電話必須連上電話線\(連網(wǎng)\)
4.開始在家等電話\(開始監(jiān)聽電話listen\) 5.電話鈴響了,接起電話,聽到對方的聲音\(接受新連接\)
打電話方(socket客戶端):
1.首先你得有個電話\(生成socket對象\) 2.輸入你想撥打的電話\(connect 遠程主機ip+port\) 3.等待對方接聽 4.say “hi
約么,我有七天酒店的打折卡噢~”\(send\(\) 發(fā)消息。。。\) 5.等待回應——》響應回應——》等待回應。。。。
二、Socket套接字方法
1、socket實例類
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
family(socket家族)
* socket.AF_UNIX
:用于本機進程間通訊,為了保證程序安全,兩個獨立的程序(進程)間是不能互相訪問彼此的內(nèi)存的,但為了實現(xiàn)進程間的通訊,可以通過創(chuàng)建一個本地的socket來完成。
* socket.AF_INET
:(還有AF_INET6被用于ipv6,還有一些其他的地址家族,不過,他們要么是只用于某個平臺,要么就是已經(jīng)被廢棄,或者是很少被使用,或者是根本沒有實現(xiàn),所有地址家族中,AF_INET是使用最廣泛的一個,python支持很多種地址家族,但是由于我們只關心網(wǎng)絡編程,所以大部分時候我么只使用AF_INET)。
socket type 類型
* socket.SOCK_STREAM # for TCP
* scoket.SOCK_DGRAM # for UDP
* socket.SOCK_RAW #
原始套接字,普通的套接字無法處理ICMP、IGMP等網(wǎng)絡報文,而SOCK_RAW可以;其次,SOCK_RAW也可以處理特殊的IPv4報文;此外,利用原始套接字,可以通過IP_HDRINCL套接字選項由用戶構造IP頭。
* socket.SOCK_RDM #
是一種可靠的UDP形式,即保證交付數(shù)據(jù)但不保證順序。SOCK_RAM用來提供對原始協(xié)議的低級訪問,在需要執(zhí)行某些特殊操作時使用,如發(fā)送ICMP報文。SOCK_RAM通常僅限于高級用戶或管理員運行的程序使用。
* socket.SOCK_SEQPACKET # 廢棄了。
Only SOCK_STREAM and SOCK_DGRAM appear to be generally useful.
proto=0
可忽略,特殊用途才考慮。
fileno=None
可忽略,特殊用途才考慮。
2、服務端套接字函數(shù)
設s為socket實例化的一個對象
* s.bind() 綁定(主機,端口號)到套接字。
* s.listen() 開始TCP監(jiān)聽。
* s.accept() 被動接收TCP客戶的連接,(阻塞式)等待連接的到來。
3、客戶端套接字函數(shù)
設s為socket實例化的一個對象
* s.connect() 主動初始化TCP服務器連接。
* s.connect_ex() 是connect()函數(shù)的擴展版本,出錯時返回出錯碼,而不是拋出異常。
4、公共用途的套接字函數(shù)
設s為socket實例化的一個對象
* s.recv() 接收數(shù)據(jù)。
* s.send() 發(fā)送數(shù)據(jù)(send在待發(fā)送數(shù)據(jù)量大于己端緩存區(qū)剩余空間時,數(shù)據(jù)丟失,不會發(fā)完)
* s.sendall()
發(fā)送完整的TCP數(shù)據(jù)(本質(zhì)就是循環(huán)調(diào)用send,sendall在待發(fā)送數(shù)據(jù)量大于己端緩存區(qū)剩余空間時,數(shù)據(jù)不丟失,循環(huán)調(diào)用send直到發(fā)完)。
* s.recvform() Receive data from the socket. The return value is a pair
(bytes, address)
* s.getpeername() 連接到當前套接字的遠端的地址。
* s.close() 關閉套接字。
* socket.setblocking(flag) # True or False,設置socket為非阻塞模式。
* socket.getaddrinfo(host, port, family=0, type=0, proto=0, flags=0)
返回遠程主機的地址信息,例如:socket.getaddrinfo('luffycity.com', 80)。
* socket.getqdn() 拿到本機的主機名。
* socket.gethostbyname() 通過域名解析ip地址。
熱門工具 換一換