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(真实数据长度)

 

 

 

 

 

 

posted @ 2019-12-05 17:54  treeter  阅读(651)  评论(0编辑  收藏  举报