一、TCP协议
TCP协议建立双向通道
1.三次握手,建立连接:
客户端向服务端发送建立连接的请求
服务端返回收到请求的信息给客户端,并且发送往客户端建立连接的请求
客户端接收到服务端发来的请求,返回接成功给服务端,完成双向连接
2.反馈机制:
客户端往服务端发送请求,服务端必须返回响应,
告诉客户端收到请求了,并且将服务端的数据一并返回给客户端。
洪水攻击:指的是通过伪造大量的请求,往对方服务器发送请求,导致对方服务器响应跟不上,以至于瘫痪。
半连接池listen: 限制用户在同一个时间段内的访问数量。
3.四次挥手,断开连接:
客户端向服务端发送断开连接的请求
服务端返回收到请求的信息给客户端
服务端确认所有数据接收完成以后,再发送同意断开连接的请求给客户端
客户端返回收到断开连接的请求,给服务端。

二、socket套接字通信
1.什么是socket
socket是一个模块, 又称套接字,用来封装 互联网协议(应用层以下的层)
2.作用
socket可以实现 互联网协议应用层以下的层的工作。提高开发效率
3.使用
1 # 客户端
2 '''
3 启动服务端后再启动客户端
4 '''
5 import socket
6 # 买手机
7 client = socket.socket()
8 # 拨号
9 client.connect(
10 # 客户端的ip与port必须与服务端一致
11 ('127.0.0.1', 9527)
12 )
13 print(
14 'client is running...'
15 )
16 # 必须发送bytes类型的数据
17 # client.send('hello'.encode('utf-8'))
18 # 讲话给对方听
19 client.send(b'hello')
1 # 服务端
2 '''
3 先启动套接字服务端
4 '''
5 import socket
6 # 买手机
7 server = socket.socket()
8 # 绑定手机卡
9 server.bind(
10 # 相当于手机号码
11 # 127.0.0.1 == localhost 本机回环地址
12 # 单机测试下: 127.0.0.1
13 ('127.0.0.1', 9527)
14 )
15 # 半连接池
16 server.listen(5) # 最多5个人坐椅子, 实际上==6
17 print(
18 'server is running...'
19 )
20 # 等待电话接入
21 # conn: 指的是服务端往客户端的管道
22 conn, addr = server.accept()
23 # 接听对方讲话的内容
24 # data客户端发送过来的消息
25 data = conn.recv(1024) # 可接受一次1024bytes的数据
26 print(data)
27 # 挂电话
28 conn.close()
进阶循环套接字版本
服务端
'''
注意:
客户端先一次发送,服务端得先一次接受,再发送消息。
'''
import socket
# 买手机
server = socket.socket()
# 绑定手机卡
server.bind(
# 相当于手机号码
# 127.0.0.1 == localhost 本机回环地址
# 单机测试下: 127.0.0.1
('127.0.0.1', 9527)
)
# 半连接池
server.listen(5) # 最多5个人坐椅子, 实际上==6
print('server is running...')
# 等待电话接入
# conn: 指的是服务端往客户端的管道
conn, addr = server.accept()
while True:
# 接听对方讲话的内容
# data客户端发送过来的消息
data = conn.recv(1024) # 可接受一次1024bytes的数据
if len(data) == 0:
break
if data.decode('utf-8') == 'q':
break
print(data)
send_data = input('服务端>>>:')
# 服务端往客户端发送消息
conn.send(send_data.encode('utf-8'))
# 挂电话
conn.close()
# 客户端
'''
启动服务端后再启动客户端
'''
import socket
# 买手机
client = socket.socket()
# 拨号
client.connect(
# 客户端的ip与port必须与服务端一致
('127.0.0.1', 9527)
)
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)
client.close()
最终循环套接字版本
1 # 服务端
2 '''
3 注意:
4 客户端先一次发送,服务端得先一次接受,再发送消息。
5 '''
6 import socket
7 # 买手机
8 server = socket.socket()
9 # 绑定手机卡
10 server.bind(
11 # 相当于手机号码
12 # 127.0.0.1 == localhost 本机回环地址
13 # 单机测试下: 127.0.0.1
14 ('127.0.0.1', 9527)
15 # 局域网内测试
16 # ('192.168.12.202', 9527)
17 )
18 # 半连接池
19 server.listen(5) # 最多5个人坐椅子, 实际上==6
20 print('server is running...')
21
22 # 循环实现可接受多个用户访问
23 while True:
24 # 等待电话接入 ---> 接入客户端
25 # conn: 指的是服务端往客户端的管道
26 conn, addr = server.accept()
27 print(addr)
28 # 循环实现循环通信
29 while True:
30 try: # 监听代码块是否有异常出现
31 # 接听对方讲话的内容
32 # data客户端发送过来的消息
33 data = conn.recv(1024) # 可接受一次1024bytes的数据
34 if len(data) == 0:
35 break
36 if data.decode('utf-8') == 'q':
37 break
38 print(data.decode('utf-8'))
39 send_data = input('服务端>>>:')
40 # 服务端往客户端发送消息
41 conn.send(send_data.encode('utf-8'))
42 # 捕获异常信息,并打印 # e: 报错信息
43 except Exception as e:
44 print(e)
45 break
46 # 挂电话
47 conn.close()
48
49
50 # 客户端
51 '''
52 启动服务端后再启动客户端
53 '''
54 import socket
55 # 买手机
56 client = socket.socket()
57 # 拨号
58 client.connect(
59 # 客户端的ip与port必须与服务端一致
60 ('127.0.0.1', 9527)
61 )
62 print('client is running...')
63 # 必须发送bytes类型的数据
64 # 讲话给对方听
65 while True:
66 send_data = input('客户端>>>:')
67 client.send(send_data.encode('utf-8'))
68 data = client.recv(1024)
69 if data.decode('utf-8') == 'q':
70 break
71 if len(data) == 0:
72 break
73 print(data.decode('utf-8'))
74 client.close()
三、粘包问题
- 1) 问题: 无法确认对方发送过来数据的大小。
- 2) 问题: 在发送数据间隔短并且数据量小的情况下,会将所有数据一次性发送。
解决: 确认对方数据的大小。
解决粘包问题(struct模块)
- 无论哪一端先发送数据
- 客户端
- 1) 先制作报头,并发送 (struct)
- 2) 发送真实数据
- 服务端:
- 1) 接收报头,并解包获取 真实数据长度
- 2) 根据真实数据长度 接收真实数据,recv(真实数据长度)