socket套接字
端口号:
0-1024: 禁用,操作系统在用
用8000以上的
软件固定的端口号:
django: 8000
mysql: 3306
redis: 6379
flask: 5000
tomcat:8080
mongodb:27017
1.TCP协议:三次握手,四次挥手
TCP协议建立双向通道
三次握手,建立连接:
1.客户端向服务端发送建立连接的请求
2.服务端返回接收请求的信息给客户端,并且发送送往客户端建立连接的请求
3.客户端接收到服务端发来的请求,返回同意信息给服务端,完成双向连接
反馈机制:
客户端往服务端发送请求,服务端必须返回响应,告诉客户端收到请求了,并且将服务端的数据一并返回给客户端
一次请求必须要有一次响应
缺点:
洪水攻击:
指的是通过伪造大量的请求,往对方服务器发送请求,导致对方服务器响应跟不上,以至于瘫痪
在linux系统中有一个参数可以限制
半连接池listen:限制用户在同一时间段内的访问数量
四次挥手,断开连接
1.客户端向服务端发送断开连接的请求
2.服务端返回收到请求的信息给客户端
3.服务器确认所有的数据接收完成后,再发送同意断开连接的请求给客户端,同时发送断开连接的请求
4.客户端返回同意断开连接的请求,给服务端
socket套接字通信:
什么是socket:
socket是一个模块,又称套接字,用来封装互联网协议(应用层以下的层)
为什么要有socket?
socket可以实现,互联网协议应用层以下的层的工作,提高开发效率
怎么使用socket?
import socket
写socket套接字:
client和server
粘包问题:
1.无法确认对方发过来数据的大小
2.再发送数据间隔短并且数据量小的情况下,会将所有的数据一次性发送
解决: 确认对方数据的大小
解决粘包问题(struct模块)
无论哪一段先发送数据
客户端:
1)先制作报头,并发送(struct)
2)发送真实数据
服务端:
1)接收报头,并解包获取真实数据长度
2)根据真实数据长度接收真实数据
rev(真实数据长度)
server端
import socket
server = socket.socket()
server.bind(
('127.0.0.1', 9898)
)
# 半连接池
server.listen(5) # 实际上可以允许6个访问
print(
'serve is running!'
)
# conn:指的是服务端通往客户端的管道
# 接收客户端链接
conn, addr = server.accept()
print(addr)
# 接收内容
ret = conn.recv(1024)
print(
ret.decode('utf-8')
)
# 发送数据
conn.send('你好'.encode('utf-8'))
conn.close()
client端
import socket
client = socket.socket()
client.connect(
('127.0.0.1', 9898)
)
print(
'client is running!'
)
# 必须发送bytes的数据
# client.send('hello'.encode('utf-8'))
client.send('hello'.encode('utf-8'))
# 接收数据
ret = client.recv(1024)
print(ret.decode('utf-8'))
client.close()
结果:
server端:
serve is running!
('127.0.0.1', 63794)
hello
client端:
client is running!
你好
完整的:
server端
import socket
server = socket.socket()
server.bind(
('127.0.0.1', 9556)
)
print('server is running!')
# 半连接池
server.listen(5)
# 循环实现可以接受多个用户访问
while True:
conn, addr = server.accept()
print(addr)
while True:
# 抛出异常处理
try:
# 接收客户端发送的数据
data = conn.recv(1024)
data = data.decode('utf-8')
if len(data) == 0:
break
if data == 'q':
break
print(data)
# 再由服务端给客户端发送数据
send_data = input('服务端》》:').strip()
conn.send(send_data.encode('utf-8'))
except Exception as e:
print(e)
conn.close()
client端:
import socket
client = socket.socket()
client.connect(
('127.0.0.1', 9556)
)
print('client is running!')
while True:
# 用户输入
send_data = input('客户端》》:').strip()
# 客户端发送信息
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()
运行结果:
client:
client is running!
客户端》》:你是谁
我是你爸爸
客户端》》:去你的
fuck your mouth
客户端》》:
server:
server is running!
('127.0.0.1', 64030)
你是谁
服务端》》:我是你爸爸
去你的
服务端》》:fuck your mouth
解决粘包问题:
client:
import socket
import struct
import json
client = socket.socket()
client.connect(
('127.0.0.1', 9000)
)
while True:
movie_name = input('请输入上传电影的名字: ')
# 伪装电影真实数据
movie_len = 1000000
send_dic = {
'movie_name': movie_name,
'movie_len': movie_len
}
# 序列化
json = json.dumps(send_dic)
print(json)
print(json.encode('utf-8'))
print(len(json.encode('utf-8')))
json_bytes = json.encode('utf-8')
# 做一个报头
header = struct.pack('i', len(json_bytes))
# 先发送报头
client.send(header)
# 后发送真实数据
client.send(json_bytes)
server:
import socket
import json
import struct
server = socket.socket()
server.bind(
('127.0.0.1', 9000)
)
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(dict)的真实长度
json_bytes_data = conn.recv(json_len)
# 将bytes类型数据转为json数据
json_data = json_bytes_data.decode('utf-8')
# 反序列化 json ---> dict
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()