基本模型:

OSI七層模型

先有模型,再有協(xié)議
TCP/IP四層模型:先有協(xié)議和應用,再有模型
TCP:傳輸控制協(xié)議,先和目標建立連接,再傳輸數據 相當于打電話(huà)
UDP:用戶(hù)數據報協(xié)議,直接傳輸數據,目標地址在報文里面
TCP建立連接:三次握手

怎么連接的?為什么要三次?
客戶(hù)端:我要連接你
服務(wù)端:好的,我準備好了
客戶(hù)端:我建立連接了
三次保證同步,例如因為網(wǎng)絡(luò )延遲導致兩邊收到消息延后,發(fā)出的報文就可能收不到或者不知道是誰(shuí)的。
數據傳輸

斷開(kāi)連接:四次揮手

客戶(hù)端:我要關(guān)閉連接了
服務(wù)端:好的,等一下
服務(wù)端:我的數據都給你了,我要斷開(kāi)了
客戶(hù)端:好的,我斷開(kāi)了
為什么多了一次:
因為服務(wù)端可能還數據要發(fā)
到底是一次連接傳一次數據
還是一次連接傳多次數據
都可以
HTTP協(xié)議 前著(zhù) 請求一次,響應一次
Websocket 后者 服務(wù)端有新的消息就會(huì )發(fā)給建立連接的客戶(hù)端

不同主機之間通信,先用ip確定某個(gè)主機,再用端口確定某一個(gè)應用程序。
除了一些服務(wù)占用的端口外,其他端口由操作系統分配,總共65535端口
127.0.0.1 自己的主機地址
0.0.0.0 任意的主機地址


import socket sock = socket.socket() print(sock) <socket.socket fd=724, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0>

fd:正整型數據,文件描述符(唯一標識了一個(gè)socket)
domain:(域)
AF_INET ipv4
AF_INET6 ipv6
type:(套接字類(lèi)型):
SOCK_RAW 原始套接字 ——>使用原始套接字時(shí)候調用,原始套接字也就是鏈路層協(xié)議
SOCK_STREAM 字節流套接字 ——>提供順序,可靠,雙向,基于連接的字節流。 可以支持帶外數據傳輸機制。例如:TCP協(xié)議、FTP協(xié)議
SOCK_DGRAM 數據報套接字 ——>支持數據報(無(wú)連接,不可靠的固定最大長(cháng)度的消息)例如:UDP協(xié)議
SOCK_SEQPACKET 有序分組套接字 ——>為固定最大長(cháng)度的數據報提供有序,可靠,雙向連接的數據傳輸路徑; 消費者需要利用每個(gè)輸入系統調用讀取整個(gè)分組
protocol(協(xié)議):
IPPROTO_IP IP傳輸協(xié)議
IPPROTO_TCP TCP傳輸協(xié)議
IPPROTO_UDP UDP協(xié)議
IPPROTO_SCTP SCTP傳輸協(xié)議
IPPROTO_ICMP ICMP協(xié)議
IPPROTO_IGMP IGMP協(xié)議
一般情況下IPPROTO_TCP、IPPROTO_UDP、IPPROTO_ICMP協(xié)議用的最多,UDP協(xié)議protocol就取IPPROTO_UDP,TCP協(xié)議protocol就取IPPROTO_TCP;一般情況下,我們讓protocol等于0就可以,系統會(huì )給它默認的協(xié)議。但是要是使用raw socket協(xié)議,protocol就不能簡(jiǎn)單設為0,要與type參數匹配.
三種套接字
服務(wù)端套接字:
1、監聽(tīng)套接字(相當于前臺,把你分配給連接套接字之后,繼續監聽(tīng)。如果一次連接過(guò)多,處理不過(guò)來(lái)的會(huì )掛起)
2、連接套接字(相當于和你交流的人)
客戶(hù)端套接字
服務(wù)端的端口不能由操作系統分配(一般是固定的,讓客戶(hù)端知道要請求哪個(gè)端口)
服務(wù)端套接字的綁定和監聽(tīng)

sock.bind(('',8888)) #服務(wù)端套接字綁定自己的IP地址與端口號,客戶(hù)端那邊可以不寫(xiě),內核會(huì )給它分配一個(gè)臨時(shí)的端口.不寫(xiě)就是綁定到本地,后面8888是端口
sock
<socket.socket fd=724, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('0.0.0.0', 9999)>
sock.listen(5) #開(kāi)始監聽(tīng),5表示最大掛起數

客戶(hù)端套接字

client = socket.socket() client.connect(('127.0.0.1',9999)) client <socket.socket fd=872, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 58311), raddr=('127.0.0.1', 9999)>

laddr表示本地地址,raddr表示遠程連接的地址
對于客戶(hù)端來(lái)說(shuō) laddr是客戶(hù)端ip 操作系統分配的任意端口,raddr是服務(wù)端的ip 綁定的端口
對于服務(wù)端來(lái)說(shuō) laddr是服務(wù)端的IP 綁定的端口,raddr是客戶(hù)端的IP 客戶(hù)端系統分配的端口

t = sock.accept() # 實(shí)例一個(gè)對等連接套接字,用來(lái)和客戶(hù)端通信。如果沒(méi)有客戶(hù)端連接,會(huì )處于阻塞狀態(tài) t (<socket.socket fd=676, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9999), raddr=('127.0.0.1', 58311)>, ('127.0.0.1', 58311)) conn, addr = t # conn現在是連接套接字,addr是客戶(hù)端地址和端口


client.send(b'hello') # 客戶(hù)端發(fā)送消息(字節類(lèi)型,如果是字符串記得要encode),返回數據長(cháng)度.客戶(hù)端斷開(kāi)連接之后,會(huì )發(fā)送一個(gè)b''空字節 conn.recv(1024) # 連接套接字接收消息,1024表示每次最大接收數據大小,可以通過(guò)循環(huán)把所有數據接受完,接收的消息是字節類(lèi)型,記得decode。如果沒(méi)有數據發(fā)過(guò)來(lái),會(huì )處于阻塞狀態(tài)

client.close() #客戶(hù)端程序運行完會(huì )自己斷開(kāi) conn.close() #服務(wù)端可以根據是否接到空,判斷是否需要斷開(kāi)
聯(lián)系客服