TCP协议与socket套接字
一、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(真实数据长度)