zoukankan      html  css  js  c++  java
  • Python 网络编程之 TCP 与 UDP

    Socket(套接字)

    介绍 UDP 和 TCP 协议之前,先熟悉下 socket 的基本概念。

    • 基本概念

    Socket 是通信的基石,是支持 TCP/IP 协议的网络通信的基本操作单元,在网络通信过程中端点的一种抽象表示。网络中使用 Socket 传输数据是一种特殊的网络 I/O。

    • 工作模式

    打开open -> 读写write/read -> 关闭close

    • 五种信息

    socket 包括了数据传输必须的五元组,分别为源IP、源端口、目的IP、目的端口和协议号

    • 通信机制

    基于流(stream)或者基于数据报(datagram)

    • python 中使用
    import socket
    
    socket.socket(...)
    

    UDP

    UDP(User Datagram Protocol) 用户数据报协议,是一种面向无连接的协议,提供简单不可靠的信息传输服务,发送后不会确认信息是否到达。

    UDP 通信模型中,在通信开始之前,不需要建立相关的链接,只需要发送数据即可,类似于生活中"写信"。

    • 使用 socket 使用 UDP 的收发数据,先看原理图

    • 客户端代码实现
    # 客户端 发送数据
    # 1.创建udp套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    while True:
        send_data = input("请输入要发送的数据:")
        if send_data == 'exit':
            break
        # 2.发送数据
        udp_socket.sendto(send_data.encode(), ("192.168.1.110", 8080)) # 对方的ip和port
        # 3.关闭套接字
    udp_socket.close()
    
    • 服务端代码实现
    # 服务端 接收数据
    HOST = '' # 空为localhost
    PORT = 7788
    ADDR = (HOST, PORT)
    BUFSIZE = 1024  # 一次接收最大的尺寸
    
    # 1.创建udp套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 2.绑定本地套接字信息
    udp_socket.bind(ADDR)  # 绑定必须是本机的ip和port
    while True:
        # 3.接收数据
        data, addr = udp_socket.recvfrom(BUFSIZE)  # 返回接收数据和发送方的地址信息
        if data.decode() == 'exit':
            print("退出")
            break
        # 打印接收的数据
        print(f"{addr[0]}:{addr[1]}", data.decode())
    # 4.关闭套接字
    udp_socket.close()
    

    套接字是可以同时收发数据,是全双工状态,在调用 recvform 之前收到数据,操作系统会将数据暂时储存起来,等到程序调用 recvform 取出数据,在调用 recvform 之后未接收到数据,程序会进入阻塞状态,等待数据的到来。

    TCP

    TCP(Transmission Control Protocol)传输控制协议,是一种面向连接的,可靠的基于字节流的传输层通信协议。

    TCP 通信需要经过创建连接数据传送终止连接三个步骤。

    TCP 通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于生活中"打电话"。 这种连接是一对一的,因此TCP不适用于广播的应用程序,基于广播的应用程序请使用 UDP 协议

    特点:

    • 面向连接(使用三次握手建立连接,连接已创建才作传输,采用四次挥手断开连接。)

    • 有序数据传输

    • 重发丢失的数据包

    • 舍弃重复的数据包

    • 无差错的数据传输

    • 阻塞/流量控制

    使用 socket 实现 TCP 的收发数据,先看原理图

    • 客户端代码实现
    # 客户端
    IPADDR = "192.168.1.110"
    PORT = 7788
    # 创建套接字
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 连接服务器,创建连接
    tcp_socket.connect((IPADDR, PORT))
    # 收发数据
    send_data = input("输入发送的数据:")
    tcp_socket.send(send_data.encode())
    # 关闭套接字,关闭连接
    tcp_socket.close()
    
    • 服务端代码实现
    # 服务端
    
    IPADDR = “”  # 默认localhost
    PORT = 7788
    BUFSIZE = 1024  # 一次接收最大的尺寸
    print('server start...')
    # 创建套接字(监听套接字)  =》买个手机
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 绑定本地信息 =》 插入手机卡
    tcp_socket.bind((IPADDR, PORT))
    # 将手机设为正常,能够响铃 =》 让默认的套接字由主动变为监听
    tcp_socket.listen(128)  # 同一时间,最大允许连接128个客户端
    
    while True:  # 循环为多个客户端服务
        print("waitting connected...")
        # 等待电话到来 =》 等待别人电话的到来,此时程序会被阻塞,等待客户端连接
        new_client_socket, client_addr = tcp_socket.accept()  # 新的专门为客户端服务的socket,客户端的addr
        # 接收客户端发送过来的请求,此时程序会阻塞等待客户端发送数据
        print("waitting recive data...")
        while True:  # 循环为同一个客户端服务多次
            recv_data = new_client_socket.recv(BUFSIZE)
            # 如果recv 解堵塞,有两种方式
            # 1.客户端发送过来数据
            # 2.客户端调用close断开连接
            if recv_data:
                print(f"【{client_addr[0]}:{client_addr[1]}】", recv_data.decode())
                # 回送一部分数据给客户端
                new_client_socket.send('收到'.encode())
            else:
                break
            # 关闭套接字
        new_client_socket.close()
        print("connect closed")
    tcp_socket.close()
    print('server end...')
    

    监听套接字负责等待有新的客户端进行连接 accept 产生的新的套接字用来为客户端服务 如果将监听套接字关闭了,那么会导致不能再次等待新客户端的到来,accept() 会失败 关闭 accept 返回的新的套接字,意味着不再为这个客户端服务。

  • 相关阅读:
    CSS 选择器
    HTML lable和fieldset
    html image和表格
    HTML a标签
    html 提交后台的标签
    HTML INPUT系列使用
    HTML内标签、换行
    HTML 头部详解
    单例模式
    const 指针的三种使用方式
  • 原文地址:https://www.cnblogs.com/izbw/p/12423682.html
Copyright © 2011-2022 走看看