zoukankan      html  css  js  c++  java
  • day 24 socket 黏包

    socket 套接字的使用:

    tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端

    server 端

    import socket
    sk = socket.socket()  # 实例化一个socket的sk对象
    sk.bind(('127.0.0.1', 10010))  # 设置IP和端口号
    sk.listen()  # 监听链接
    conn, addr  = sk.accept()  # 接收客户端链接
    
    conn.send('你好'.encode())  # conn.send(b'alex')  向客户端发送信息
    # 如果服务器是发送,客户端要对应使用接收
    ret = conn.recv(1024).decode()  # 接收客户端信息
    # 服务器是接收,客户端要对应发送
    print(ret)  # 打印客户端信息
    conn.close()  # 关闭客户端套接字
    sk.close()  # 关闭服务器套接字

    client 端

    import socket
    sk = socket.socket()  #实例化一个socket的sk对象
    sk.connect(('127.0.0.1', 10010))  # 设置ip和端口号,必须和服务器端相同
    ret = sk.recv(1024).decode()  #接收时要设置长度
    print(ret)    # 打印接收的信息
    sk.send('我好'.encode())    # 发送信息给服务器端
    sk.close()

    UDP 链接:

    server端

    import socket
    udp_sk = socket.socket(type=socket.SOCK_DGRAM)   #创建一个服务器的套接字
    udp_sk.bind(('127.0.0.1',9000))        #绑定服务器套接字
    msg,addr = udp_sk.recvfrom(1024)
    print(msg)
    udp_sk.sendto(b'hi',addr)                 # 对话(接收与发送)
    udp_sk.close()                         # 关闭服务器套接字

    client端

    import socket
    ip_port=('127.0.0.1',9000)
    udp_sk=socket.socket(type=socket.SOCK_DGRAM)
    udp_sk.sendto(b'hello',ip_port)
    back_msg,addr=udp_sk.recvfrom(1024)
    print(back_msg.decode('utf-8'),addr)

    带退出功能的聊天

    # server端:
     import socket
    sk = socket.socket()
    sk.bind(('127.0.0.1', 11111))
    sk.listen()
    conn, addr = sk.accept()
    while True:
        msg = input('>>>: ')
        conn.send(msg.encode())
        if msg == 'q': break
        ret = conn.recv(1024).decode()
        if ret ==  'q':break
        print(ret)
    conn.close()
    sk.close()
    
    
    # client端
    import socket
    sk = socket.socket()
    sk.connect(('127.0.0.1', 11111))
    while True:
        ret = sk.recv(1024).decode()
        print(ret)
        if ret == 'q': break
        msg1 = input('>>>>: ')
        sk.send(msg1.encode())
        if msg1 == 'q': break
    sk.close()

    同步服务器时间:

    #  server 端:
    
    import socket
    import time
    sk = socket.socket()
    sk.bind(('127.0.0.1', 10010))
    sk.listen()
    conn, addr = sk.accept()
    ret = conn.recv(1204).decode()
    str_time = time.strftime(ret)
    conn.send(str_time.encode())
    conn.close()
    sk.close()
    
    # client端 
    import socket
    sk = socket.socket()
    sk.connect(('192.168.13.50', 10010))
    time_type = '%Y-%m-%d'
    sk.send(time_type.encode('utf-8'))
    msg = sk.recv(1024)
    print(msg)
    sk.close()

    黏包:

    只有TCP有粘包现象,UDP永远不会粘包

    # 发送一个 ‘hello’, 然后在发送一个‘world’
    # 接收方接收到的是‘helloworld’
    # 这就叫黏包

    发送到的黏包

    接收端的黏包

    1.发送端的粘包  合包机制 + 缓存区
    2.接收端的粘包 延迟接受 + 缓存区

    总结

    黏包现象只发生在tcp协议中:

    1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。

    2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的

    黏包的解决方法:

    # 告诉客户端,你发送的数据长度
    # server端
    
    import struct
    import socket
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',9000))
    sk.listen()
    
    conn,addr = sk.accept()
    send_msg = input('>>>').encode()
    bytes_len = struct.pack('i', len(send_msg))
    conn.send(bytes_len)
    conn.send(send_msg)   # 粘包现象
    conn.send(b'world')
    conn.close()
    sk.close()
    # client 端
    
    import struct
    import socket
    
    sk = socket.socket()
    sk.connect(('127.0.0.1',9000))
    bytes_len = sk.recv(4)
    msg_len = struct.unpack('i',bytes_len)[0]
    msg = sk.recv(msg_len)
    print(msg.decode())
    msg2 = sk.recv(5)
    print(msg2)
    sk.close()

     补充:

    1.两个连续的send就会发生粘包
    2.用struct自定义协议可以解决粘包问题
    3.什么情况下我们不需要解决粘包 : 文件的传输
    4.自定义协议的进阶版本
    先发送字符串的长度,再发送字符串
    先发送json的长度,再发送json,json的字典中包含着下一条信息的长度,然后按照长度接收
  • 相关阅读:
    第八章 多线程编程
    Linked List Cycle II
    Swap Nodes in Pairs
    Container With Most Water
    Best Time to Buy and Sell Stock III
    Best Time to Buy and Sell Stock II
    Linked List Cycle
    4Sum
    3Sum
    Integer to Roman
  • 原文地址:https://www.cnblogs.com/echo2019/p/10304341.html
Copyright © 2011-2022 走看看