TCP协议 三次握手,四次挥手,socket 粘包
TCP协议 三次握手,四次挥手,socket 粘包
TCP协议
1.协议是建立双向的管道
传输层的:
-TCP协议
-UDP协议
1.1三次握手,建连结
1.客户端向服务端发送建立连结的请求;
2.服务端返回收到请求的信息给客户端,并且发送往客户端建立连接的请求;
3.客户端接收到服务发来的请求,返回连接成功给服务层,完成双向的连接。
1.2反馈机制
1.客户端往服务端发送请求,服务端必须返回响应;
2.告诉客户端收到请求了,并且将服务端色数据一并返回给客户端。
C---->S:一次的请求,必须有一次的响应
缺点:
-洪水攻击:
指的通过伪造大量的请求,往对方的服务器发送请求;
导致对方服务器想用跟不上,以至于瘫痪;
linux系统有个参数可以限制
-半连接池listen:限制用户的在同一个时间段内的访问数量。
1.3四次挥手,断开连接
1.客户端向服务端发送断开连接的请求;
2.服务端返回收到请求的信息给客户端;
3.服务端确认所有的数据发送完成以后,再发送同意断开来连接的请求给用户端;
4.客户端返回收到断开的连接的请求,给服务端。
socket
-定义:
socket是一个模块,又称套接字,用来封装互联网协议(应用层以下的层)
-作用:
-socket可以实现 互联网协议的应用层以下的层的工作;
-提高开发效率
-怎么使用:
import socket
写socket 套接字
Client
Server
注意:
端口:port 标识一台电脑计算机上的某一个软件
-0-1024禁止使用,操作系通在用
-软件的固定端口不要用:
django:8000
mysql:3306
flask:5000
redis:6379
tomcat:8080
mongodb:27017
下面这个是个socket的最总版本
先执行server 再去执行client
'''
注意:客户端先发一次发送,服务端的先一次接受,再发送信息 server
'''
import socket
#买手机 socket 也是一个类
server = socket.socket()
#绑定手机卡
server.bind(
('127.0.0.1',9528)
)#####127.0.0.1 是本地的回环地址
####局域网内测试的是192.168.12.202 ,9527
#半连接池
server.listen(5)##按照今天举得例子,最多5个人坐椅子,一个人在享受服务,实际是6个人
print('server is running....')
#循环实现可接受多个用户访问
#等待电话接入————>接入客户端
#conn 指的是服务端往客户端的管道
while True:
conn,addr = server.accept()
print(addr)
#循环实现通信
while True:
try: #监听代码块是否有异常
#接收对方讲话的内容
#data客户端端发来的信息
data = conn.recv(1024) #一次可以接收1024bytes
if len(data) == 0:
break
if data.decode('utf-8') =='q':
break
print(data.decode('utf-8')) ###这个是传过来的时候是编码用utf-8编码的,解码也要用这个解码
send_data = input('服务端>>>:')
#服务端往客户端发送信息
conn.send(send_data.encode('utf-8'))
#捕获异常的信息,并打印,报错信息
except Exception as e:
print(e)
break
#挂电话
conn.close()
下面这个是client
# '''
# 启动服务端后再启动客户端
# '''
import socket
#买手机
client = socket.socket()
#拨号
client.connect(
('127.0.0.1',9528)
)#客户端的ip和port必须和服务器保持一致
print('client is running....')
#必须发送bytes类型的数据
#必须讲给对方听
while True:
send_data = input('客户端>>>>:')
client.send(send_data.encode('utf -8'))
data = client.recv(1024)
if data .decode('utf-8') == 'q':
break
if len(data) == 0:
break
print(data.decode('utf-8'))
client.close()
粘包问题
出现的问题:
1.无法确认对方发来的数据的大小
2.在发送数据间隔短并且数量小的情况下,会将所有数据一次性发送
解决办法
-粘包(struct模块)
-无论那一端发送数据
-客户端:
1.先制作报头,在发生
2.发送真实的数据
-服务端
1.接收报头,并解包获取真实的长度 recv(报头)
2.根据真实的长度,接收真实的数据 recv(真实的数据长度)
粘包的举例 电影
先执行server 再去执行client
下面这个server
import socket
import json
import struct
server = socket.socket()
server.bind(
('127.0.0.1',9002)
)
server.listen(5)
while True:
conn,addr = server.accept()
print(addr)
while True:
try:
#获取客户传过来的报头
header = conn.recv(4)
#解包获取真实的数据长度
json_len = struct.unpack('i',header)[0]
#接收json的真实长度
json_bytes_data = conn.recv(json_len)
#将bytes类型转化成json数据
json_data = json_bytes_data.decode('utf-8')
#反序列化
back_dic = json.loads(json_data)
print(back_dic)
print(back_dic.get('movie_len'))
# movie_data = conn.recv(back_dic.get('movie_len'))
# print(movie_data)
except Exception as e:
print(e)
break
conn.close()
>>>>>>>>>>>>>>>>>>>>>
('127.0.0.1', 53140)
{'movie_name': '太阳', 'movie_len': 100000}
100000
{'movie_name': '中国', 'movie_len': 100000}
100000
下面这个是client
import socket
import struct
import json
client = socket.socket()
client.connect(
('127.0.0.1',9002)
)
while True:
movie_name = input('请输入电影的名字:')
#伪装的一个电影的真实长度
movie_len = 100000
send_dic = {
'movie_name': movie_name,
'movie_len': movie_len
}
#序列化
json1 = json.dumps(send_dic)
print(json1)
print(json1.encode('utf-8'))
print(len(json1.encode('utf-8')))
json1_bytes = json1.encode('utf-8')
#做一个报头
header = struct.pack('i',len(json1_bytes))
#先发送包头
client.send(header)
#再发送真实的数据
client.send(json1_bytes)
>>>>>>>>>>>>>>>>>>>>>>
请输入电影的名字:太阳
{"movie_name": "\u592a\u9633", "movie_len": 100000}
b'{"movie_name": "\\u592a\\u9633", "movie_len": 100000}'
51
请输入电影的名字:中国
{"movie_name": "\u4e2d\u56fd", "movie_len": 100000}
b'{"movie_name": "\\u4e2d\\u56fd", "movie_len": 100000}'
51
与终端的相关联的举例
下面这个是server
import socket
import subprocess
server = socket.socket()
server.bind(
('127.0.0.1',9000)
)
server.listen(5)
while True:
conn,addr = server.accept()
while True:
try:
cmd = conn.recv(10)
if len(cmd) == 0:
continue
cmd = cmd.decode('utf-8')
if cmd == 'q':
break
#调用subprocess连接终端,对终端进行操作,并获取操作后正确或者错误的结果
obj = subprocess.Popen(
cmd,shell = True,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
)
#结果交给result变量名
result = obj.stdout.read()+obj.stderr.read()####stuout是正确的结果,stuerr是错误的结果,这个result 是正确的和错误的相加,无论对错都能打印一个结果
print(len(result))
#gbk
print(result.decode('gbk')) ###window系统 终端默认的编码是gbk
conn.send(result)
except Exception as e:
print(e)
break
下面这个是client
import socket
client = socket.socket()
client.connect(
('127.0.0.1',9000)
)
while True:
cmd = input('客户输入的内容:')
client.send(cmd.encode('utf-8'))
data = client.recv(19190)
print(len(data))
print(data.decode('gbk'))