网络通讯协议与套接字

网络通讯协议与套接字

一、基本概念

  • 网络

    网络就是一种辅助双方或者多方能够连接在一起的工具, 为了让在不同的电脑上运行的软件,之间能够互相传递数据,就需要借助网络的功能

  • IP 地址

    • IP地址的概念和作用

      地址就是用来标记地点的, 用来在网络中标记一台电脑,比如192.168.1.1;在本地局域网上是唯一的。

    • IPV4IPV6 的主要区别

      IPv4地址的概念是在1980年代初期提出的。即使有新版本的IP地址,IPv4地址仍然是Internet用户使用最广泛的地址; IPv4 可以分配40亿个唯一地址,随着互联网的发展。2011年IP地址已经枯竭。
      	IPv4是32位IP地址; 分为四段,每段8位,以十进制形式表示,每段之间以点隔开,例如:192.168.0.1
      	IPv6是128位IP地址,分为八段,每段16位,以十六进制形式表示,每段之间以冒号隔开,例如:ffff:ffff:ffff:ffff:ffff:ffff:ffff:0001. 可以创建大约3.4×10e38个地址。
      
    • IP地址的分类 (IPV4)

      IP地址分类

    • 私有 IP

      在这么多网络IP中,国际规定有一部分IP地址是用于我们的局域网使用,也就

      是属于私网IP,不在公网中使用的,它们的范围是:

      10.0.0.0~10.255.255.255
      
      172.16.0.0~172.31.255.255
      
      192.168.0.0~192.168.255.255
      
    • 说明

      • IP 地址127.0.0.1~127.255.255.255用于回路测试,
      • 127.0.0.1可以代表本机IP地址,可是使用 ping 127.0.0.1 测试本机的网卡和IP协议
      • 查看本机IP地址 ipconfig ifconfig
  • 端口port

    • 什么是端口

      端口就好一个房子的门,是出入这间房子的必经之路; 用于区分一个主机下的不同网络服务。

    • 端口号

      端口是通过端口号来标记的,端口号只有整数,范围是从0到65535

    • 端口的分配

      • 知名端口

        知名端口是众所周知的端口号,范围从0到1023

        80 端口分配给HTTP服务
        21 端口分配给FTP服务
        
      • 动态端口

        动态端口的范围是从1024到65535,一般不固定分配某种服务,而是动态分配

二、网络通讯层次模型

网络通讯层次模型

  • 数据在网络中的传输过程

    网络通讯过程

    • 数据在传输的过程中是以包的形式传输的,所以数据包是一个信息单位,作为一个整体,从网络中的一个设备传送给另一个设备。
    • 数据包创建于应用层,然后经过下面六层的一层层包装,以增加自己的信息(信头),最后通过网线或光纤发给对方的物理层,然后又再向上一次一次的拆包。

三、Socket

  • 什么是socket

    socket(简称 套接字) 是进程间通信的一种方式,它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页、QQ 聊天、收发 email 等等
    
  • 创建套接字

    • 在 Python 中 使用socket 模块的函数 socket 就可以完成

      import socket
      socket.socket(AddressFamily, Type)
      
    • 参数说明

      • Address Family:可以选择 AF_INET(用于 Internet 进程间通信) 或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
      • Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)
  • 创建套接字代码演练

    import socket
    
    # 创建tcp的套接字
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 创建udp的套接字
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    # 关闭套接字
    s.close()
    
  • 套接字使用流程

    • 创建套接字对象
    • 使用套接字发送/接收数据
    • 关闭套接字

四、UDP通信

  • UDP通讯模型

    UDP通讯流程

  • UDP通讯流程分析

    • 创建UDP套接字对象
    • 绑定端口(客户端不需要绑定)
    • 发送/接收 数据
    • 关闭套接字
  • 代码演练

    # 【本机环境运行】
    # 使用网络调试助手作为客户端
    from socket import *
    
    udp_socket = socket(AF_INET, SOCK_DGRAM)
    
    # 绑定端口(一般作为服务器才绑定)
    udp_socket.bind(("127.0.0.1", 8888))
    dest_addr = ("127.0.0.1", 8080)
    
    send_data = input("please input send data: ")
    
    # win 默认按gbk编码
    udp_socket.sendto(send_data.encode("utf8"), dest_addr)
    # 接收客户端的数据
    recv_data = udp_socket.recvfrom(1024)
    
    content, addr = recv_data
    print(addr)
    print(content.decode("utf8"))
    
    udp_socket.close()
    

五、TCP通信

  • TCP通讯模型

    TCP通讯流程

  • UDP通讯流程分析

    • 作为服务器
      • 创建TCP套接字对象
      • bind绑定IP和端口
      • 设置套接字为监听套接字
      • 等待客户端连接(连接成功得到服务套接字和客户端地址)
      • 使用服务套接字接收/发送数据
      • 关闭监听套接字和服务套接字
    • 作为客户端
      • 创建TCP套接字对象
      • 连接服务器
      • 使用套接字发送/接收数据
      • 关闭套接字
  • 代码演练

    • 服务器实现

      # 【本机环境运行】
      from socket import *
      
      # 创建TCP套接字
      tcp_server_socket = socket(AF_INET, SOCK_STREAM)
      
      # 绑定IP和端口
      tcp_server_socket.bind(("127.0.0.1", 8888))
      
      # 将套接字设置为监听状态
      tcp_server_socket.listen(128)
      
      # 等待连接请求,获取服务套接字
      client_socket, client_addr = tcp_server_socket.accept()
      
      while True:
          recv_data = client_socket.recv(1024).decode()
          # 客户端调用close; recv_data为 ''
          if not recv_data:
              break
      
          print(f"{client_addr} : {recv_data}")
      
      # 关闭服务套接字和监听套接字
      client_socket.close()
      tcp_server_socket.close()
      
  • 客户端实现

    # 【本机环境运行】
    from socket import *
    
    # 创建TCP套接字
    tcp_client_socket = socket(AF_INET, SOCK_STREAM)
    
    # 连接TCP服务器
    tcp_client_socket.connect(("127.0.0.1", 8888))
    
    while True:
        send_data = input("please enter the sent data: ")
        if send_data == "exit":
            break
    
        tcp_client_socket.send(send_data.encode())
    
    # 关闭套接字
    tcp_client_socket.close()
    

六、TCP的3次握手和4次挥手

三次握手四次挥手

七、TCP长连接和短连接

  • 短连接

    建立连接 —— 数据传输 —— 关闭连接 ... 建立连接 —— 数据传输 —— 关闭连接
    
  • 长连接

    建立连接 —— 数据传输 ...(保持连接)... 数据传输 —— 关闭连接
    

八、UDPTCP通信区别

  • 面向连接(确认有创建三方交握,连接已创建才作传输。)
  • 有序数据传输
  • 重发丢失的数据包
  • 舍弃重复的数据包
  • 无差错的数据传输
  • 阻塞/流量控制

九、说明

  • TCP 服务器一般情况下都需要绑定,否则客户端找不到这个服务器
  • TCP 客户端一般不绑定,因为是主动链接服务器,所以只要确定好服务器的IPPORT 等信息就好,本地客户端可以随机
  • TCP 服务器中通过 listen 可以将 socket 创建出来的主动套接字变为被动的,这是做TCP 服务器时必须要做的
  • 当客户端需要链接服务器时,就需要使用connect进行链接,UDP 是不需要链接的而是直接发送,但是TCP必须先链接,只有链接成功才能通信
  • 当一个TCP客户端连接服务器时,服务器端会有1个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务
  • listen后的套接字是被动套接字,用来接收新的客户端的链接请求的,而accept返回的新套接字是标记这个新客户端的
  • 关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器,但是之前已经链接成功的客户端正常通信。
  • 关闭accept返回的套接字意味着这个客户端已经服务完毕
  • 当客户端的套接字调用close后,服务器端会recv解堵塞,并且返回的长度为0,因此服务器可以通过返回数据的长度来区别客户端是否已经下线
posted @ 2024-08-20 12:32  CSMrDong  阅读(8)  评论(0编辑  收藏  举报