个人理解基于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()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章