• python基础-网络编程part02


    TCP协议

    TCP是传输控制协议,建立双向通道。

    三次握手,建立连接

    • 客户端向服务端发送建立连接的请求
    • 服务端接收请求返回确认信息给客户端,并向客户端发送建立连接的请求
    • 客户端接收请求返回确认信息给服务端

    反馈机制:一次请求必须有一次响应。即收到请求后,必须告知对方已收到请求。

    四次挥手,断开连接

    • 客户端向服务端发送断开连接的请求
    • 服务端接收请求返回确认信息发给客户端
    • 服务端确认所有数据接收完毕以后,发送断开连接的请求给客户端
    • 客户端接收请求返回确认信息给服务端

    socket套接字通信

    定义:python内置的模块,又称套接字,用来封装互联网协议(应用层以下的层)

    作用:实现互联网协议应用层以下的工作,提高开发效率

    使用方式:见代码

    • 服务端server.py
    import socket
    
    # 获取socket 对象
    server = socket.socket()
    # 绑定服务端ip 地址和端口
    # 127.0.0.1是回环地址,表示本机ip
    server.bind(('127.0.0.1', 8080))
    # 半连接池,表示可以同时让多少个客户端访问。
    # 一个客户端正在交互,剩下的等待交互,listen(n):n+1个客户端
    server.listen(5)
    # 阻塞,直到客户端访问,返回连接请求和客户端IP
    conn, client = server.accept()
    # 接收客户端发送的信息并打印
    # 接收默认最大字节数:1024(可根据内存自行调整)
    client_data = conn.recv(1024).decode('utf-8')
    print(f"来自客户端的消息:{client_data}")
    # 向客户端发送消息
    send_msg = input("请输入指令>>>>>:").strip().encode('utf-8')
    conn.send(send_msg)
    
    # 关闭连接
    conn.close()
    # 关闭服务
    server.close()
    
    • 客户端client.py
    import socket
    
    # 创建socket对象
    client = socket.socket()
    # 向服务端请求连接
    client.connect(('127.0.0.1', 9527))
    # 向服务端发送数据,send只接收二进制数据
    client_msg = input("请输入要发送给服务端的信息>>>>:").strip()
    client.send(client_msg.encode('utf-8'))
    # 接收服务端返回的数据
    # 接收默认最大字节数:1024(可根据内存自行调整)
    client_data = client.recv(1024).decode('utf-8')
    print(f"来自服务端的消息:{client_data}")
    # 关闭连接
    client.close()
    

    注意:

    • 先启动服务端,再启动客户端
    • 一次数据请求必须有一次响应,服务端和客户端不能同时发送请求或同时接收请求

    粘包现象

    • 现象一:数据多次发送时间间隔短,且量少时,接送一次读取了信息,后续读取记录为空
    # 客户端.py
    import socket
    
    server = socket.socket()
    server.connect(("127.0.0.1", 9527))
    
    # 连续发送
    server.send(b"hello")
    server.send(b"hello")
    server.send(b"hello")
    
    server.close()
    
    # 服务端.py
    import socket
    from socket import SOL_SOCKET
    from socket import SO_REUSEADDR
    
    server = socket.socket()
    server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    server.bind(("127.0.0.1", 9527))
    server.listen(5)
    conn, client = server.accept()
    
    data1 = conn.recv(1024)
    data2 = conn.recv(1024)
    data3 = conn.recv(1024)
    
    print(data1)
    print(data2)
    print(data3)
    
    conn.close()
    server.close()
    

    输出结果

    b'hellohellohello'
    b''
    b''
    
    • 现象二:当发送数据的字节数超出每次接收的最大限制数,会将上次没有接收完的记录在下次接收
    # 客户端.py
    import socket
    
    client = socket.socket()
    client.connect(('127.0.0.1', 9527))
    client.send(b'hello world!')
    client.send(b'lift is smart!')
    client.close()
    
    # 服务端.py
    import socket
    from socket import SOL_SOCKET
    from socket import SO_REUSEADDR
    
    server = socket.socket()
    server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    server.bind(('127.0.0.1', 9527))
    server.listen(5)
    
    conn, client = server.accept()
    
    re_data1 = conn.recv(5).decode('utf-8')
    re_data2 = conn.recv(5).decode('utf-8')
    
    print(re_data1)
    print(re_data2)
    conn.close()
    server.close()
    

    输出结果

    hello
     worl
    

    struct模块—解决粘包问题

    定义:python内置的模块,可以将 固定长度的数据,打包成固定格式的长度

    作用:将真实数据,做成一个固定长度的报头,客户端发送给服务端,服务端可以接收报头(反之亦然)。然后对报头进行解包,获取真实数据的长度,进行接收即可。

    使用,以现象二举例(实质都一样解决)

    # 客户端.py
    import socket
    import struct
    
    client = socket.socket()
    client.connect(('127.0.0.1', 9527))
    msg1 = 'hello world!'
    # 使用struct模块中的pack方法,模式‘i’表示4个字节
    # 将要发送的数据长度打包成一个header
    header1 = struct.pack('i', len(msg1))
    # 先将报头发送给服务端
    client.send(header1)
    # 再将真实数据发送给服务端
    client.send(msg1.encode('utf-8'))
    
    # 服务端.py
    import socket
    import struct
    
    server = socket.socket()
    server.bind(('127.0.0.1', 9527))
    server.listen(5)
    conn, client = server.accept()
    
    # 读取报头
    header = conn.recv(4)
    # 使用struct.unpack 解析真实数据长度
    header_len = struct.unpack('i', header)[0]
    
    # 读取真实数据
    re_data = conn.recv(header_len)
    
    print(re_data.decode('utf-8'))
    conn.close()
    server.close()
    
  • 相关阅读:
    String类的常用方法(P小写)
    二维数组:判断是否有目标数
    java实现输入年份判断在哪一天(正则表达式待改进)
    Java实现八进制正整数转化为十进制数
    时钟和定时器
    电路的频率响应---带宽的定义
    stm32两轮平衡车资料
    二阶常系数齐次线性微分方程的解法
    同步积分
    陀螺仪信号解调
  • 原文地址:https://www.cnblogs.com/xiaodan1040/p/11991637.html
Copyright © 2020-2023  润新知