個人理解基於socket的網絡編程及三次握手及四次揮手

如果把socket比做成打電話,可以理解成這樣:
在這裏插入圖片描述

TCP協議的三次握手與四次揮手

TCP協議在傳輸層,
首先客戶端會發送一個SYN_SENT
服務端收到SYN請求,進行SYN_RECV,然後服務端會回一個SYN,並且ACK = x+1,SYN代表要發起新的鏈接,服務端接收到之後,確認允許建立連接,客戶端到服務端就建立成功了,但服務端到客戶端也要建立一個請求,所以第二條箭頭代表“一次確認,一次服務端到客戶端發起新的鏈接的SYN請求”兩個合到了一起,客戶端就進入了ESTABLISHED狀態,意味着客戶端到服務端那條線就建立成功了
第三次客戶端同意了服務端的鏈接請求,然後服務端就也進入了一個ESTABLISHED狀態
三次握手如下圖:
在這裏插入圖片描述
回到電話舉例子:
服務端:

import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#買手機

socket.AF_INET代表基於網絡通信,SOCK_STREAM代表基於TCP協議
phone.bind(('192.168.222.102',8000))#綁定手機卡
bind服務端的標識,就是ip地址加端口,要寫成元祖
phone.listen(5)#開機
listen(5)代表最多可以有5個電話在後面等着
有一個攻擊叫做洪水攻擊,就是在一直給你的服務端發起請求,你的服務端在接到請求後需要響應請求
如果一個黑客一次性給你模擬發送了10000條SYN請求,之後關閉掉客戶端你的服務端就會一直髮送響應請求
listen就是半連接池(backlog)的一種狀態,如果瞬間接到10000條請求會瞬間把5條沾滿,這時候一般是修改半連接池的數量或者縮小返回的次數
conn,addr = phone.accept()#等電話,拿到一個電話連接
accept會拿到一個“電話鏈接”,還有對方的“手機號”,accept相當於拿到了一個TCP鏈接,拿到了連接以後就要傳輸數據了(基於三次握手建立好之後)

conn.send(input().encode('utf-8'))
msg = conn.recv(1024)#收消息
print('客戶端發來的消息是',msg)

收發消息需要用鏈接來收消息,recv代表接收,1024代表最多收多少字節

conn.send(msg.upper())#發消息
conn.close()#掛電話,就相當於關閉三次握手
phone.close()#關機

客戶端:

import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('192.168.222.102',8000))#客戶端直接開始打電話
phone.send('hello'.encode('utf-8'))
date = phone.recv(1024)
print('收到服務端發來的消息',date)

四次揮手就是誰先發完包,誰來主動斷開接口(見上圖)
第一條線代表:客戶端發送FIN請求給副段,客戶端進入FIN——WAIT_1狀態,這個代表主動斷開鏈接的請求
服務端會回一個ACK,回到了客戶端即代表斷開了從客戶端到服務端的一條線,客戶端進入FIN_WAIT2狀態,代表被動斷開鏈接
第三條線代表服務端主動發送一條斷開鏈接的請求,這時候客戶端進入TIME_WAIT狀態
最後客戶端回一個ACK,TCP鏈接就算斷開了
但主動發起斷開鏈接不一定是客戶端先發起的,而是誰先發完數據誰主動發起斷開鏈接,以上文字僅僅講述的是圖內內容
但爲什麼建立連接是三次,斷開鏈接是四次呢?這是因爲斷開鏈接有數據上面的問題,如果斷開鏈接時將確認請求和發送請求合併到一起,會造成數據的丟失
上面的代碼如果需要循環的接收發送消息的話在接收發送消息處增加循環就可以了

from socket import *
ip_port = ('192.168.222.102',8000)
back_log = 5
buffer_size = 1024

tcp_sever = socket(AF_INET,SOCK_STREAM)
tcp_sever.bind(ip_port)
tcp_sever.listen(back_log)
print('服務端開始運行了')
conn,addr = tcp_sever.accept()#阻塞在這個位置
print('雙相連接是',conn)
print('客戶端地址是',addr)
while True:
    data = conn.recv(buffer_size)
    print('客戶端發來的消息是:',data.decode('utf-8'))#發來的是字節內容,需要解碼
    conn.send(data.upper())

conn.close()
tcp_sever.close()

客戶端:

from socket import *
ip_port = ('192.168.222.102',8000)
back_log = 5
buffer_size = 1024
tcp_client = socket(AF_INET,SOCK_STREAM)
tcp_client.connect(ip_port)
while True:
    msg = input('>>:').strip()
    tcp_client.send(msg.encode('utf-8'))
    
    data = tcp_client.recv(buffer_size)
    print('客戶端發來的消息是:',data.decode('utf-8'))
tcp_client.close()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章