zoukankan      html  css  js  c++  java
  • python31 网络编程socket使用

    复习

    1.C/S结构

    2.网络通讯

    3.OSI 开放式系统互联参考模型 七层模型

    详解:
     

    1.C/S结构

    ​ client    server
    ​ 网络通讯是为了共享数据
    ​ 拥有数据的一方 称之为服务器server
    ​ 需要数据的一方称之为客户端client
     B/S
    ​ 浏览器  服务器
    ​ 

    2.网络通讯

    ​     1.物理连接介质
    ​     2.通讯协议     (使双方能看懂数据)
    ​       协议即标准/规范   发送方和接收需要共同遵守
     

    3.OSI 开放式系统互联参考模型 七层模型

     
    ​                        应用层  表示层 会话层  传输层  网络层  数据链路层 物理层  
    ​ 
    ​ 应用层(应用层  表示层 会话层)
    ​ 传输层 
    ​ 网络层 
    ​ 网络接口层( 数据链路层 物理层  )
    ​ 

    1) 物理层

    ​ 定义一堆物理相关协议 例如接口外观等
    ​ 有了物理层就能传输二进制数据    010101010101010

    2) 数据链路层

    ​        主要是以太网协议 

    ​          1.数据传输格式   数据帧
    ​            [head  |  data]
    ​  
    ​           2.每个设备要联网 必须具备网卡  每个网卡拥有一个全球唯一的MAC地址
    ​            数据链路层通过广播的方式来查找某一台计算机 
    ​            在这一层 出现了交换机   用于组成一个局域网 
    ​             在局域网中要查找某一台计算机  就通过广播的方式
    ​             如果每一次都需要广播 就浪费资源了, 所以交换机会自动保存 网口和MAC地址表的映射关系
    ​ 
              问题: 广播风暴   没有交换机可以同时处理所有计算机 

    3) 网络层

    ​           主要是ip协议
                1. 每一台设备都必须有一个ip地址
                           格式: 四段三位点分十进制    0.0.0.0-255.255.255.255
                           其中前三段是网络号(常规情况下)   最后一段是主机号
                2.ip数据包  格式
                           [ 以太帧头  |   [head | data] ]
       
                  3.子网掩码
        ​                   用于标示iP中哪些是网络号 哪些是主机号
                                   ​ 255.255.255.0
        ​                           11111111.11111111.11111111.0000000
        ​                         1表示网络号  0标示主机号
        ​ 
                                 ​ 将ip转为二进制  子网掩码转为二进制 
        ​                            使用AND来计算两个ip是否处于同一局域网
       
        ​                         例如 1号ip 转换的结果如下
        ​                                  11011111.00001111.10101010.00001
        ​                                  11111111.11111111.11111111.0000000
                                 结果: 11011111.00001111.10101010.00000
       
        ​                       例如 1号ip 转换的结果如下
        ​                              11011111.00001111.10101010.00010
                                     ​ 11111111.11111111.11111111.0000000
                            ​ 结果: 11011111.00001111.10101010.00000
        ​ 
                      4. ARP    Address Resolution Protocol
        ​                       该协议用于将ip转为MAC地址  
        ​                     1.先 比对子网掩码 判断两个ip是否处于同一子网中
        ​                     2.1如果是  则直接在当前局域网中进行广播 
        ​                     2.2如果不是 同一局域网  则将数据包发送对方的网关   
                            ​ 2.3对方网关收到数据包后回复自己的MAC地址  
        ​                     2.4发送的交换机收到数据包在发送给 发送方 同时存储对方网关与MAC的对应关系
        ​                     2.5发送已经明确 对方网关的MAC 以及对方的IP 
        ​                     3.发送数据
        ​                      [我的MAC  对方网关的MAC [我的ip 对方的ip]]
       
                        5.路由协议:
        ​                          找到一条最佳的路径 
       
                          到此可以使用IP 来定位到全球的某一个局域网 中的某一台计算机
       

       4)传输层

        ​                   1.端口号

        ​                        每个应用程序都必须绑定一个端口号,用于标识你是谁   是qq还是微信
        ​                        端口号不能重复
        ​                       端口号就是一个整形数字   取值范围0-65535   0-1023为系统保留端口
        ​                        有了ip和端口号就能 定位到全球某一台计算机上的某一个应用程序
        ​ 

        ​                    2.传输层主要的传输协议

        ​ 
        ​                                 TCP (传输控制协议)    就像打电话
        ​                          可靠传输  
        ​                          如何保障可靠
        ​                        1.三次握手建立链接  其目的是为了确认传输路径可用
        ​                        2.传输过程中 每一个数据包都需要 确认信息 
        ​                        3.四次挥手断开链接   是为了保障双方数据都已经传输完毕 
        ​  
        ​                           传输效率低
        ​ 
        ​                                  UDP       像是校园广播 
        ​                                  用户数据报协议 
        ​                                  不关心数据是否传输成功  ,甚至不关心是否存在 
        ​  
        ​                            优点:传输效率高 

        ​ 

       5) 应用层

        ​ 数据已经通过下面各种协议传入了应用程序 
        ​ 应用程序该如何解析这些数据 ,用它们来干什么 
        ​ 这就是应用程序协议需要关心的问题了
        ​ 每个应用程序都可以自己定义自己的协议 只要客户端程序和服务器程序能看懂就行 
        ​ HTTP/HTTPS  SMTP  FTP  
       
       
       

    今日内容

    网络编程之socket

     1.socket在OSI中的位置     

    1.socket在OSI中的位置     

    1.1socket

    ​ 什么是socket  翻译为套接字
    ​ 是一套编程接口,内部封装了一堆底层协议,隐藏了内部复杂的实现细节,提供简单的使用接口
    ​ 咱们只要按照socket编程接口来编写出的代码,就已经遵循了各种协议 
    ​ 简单的说就是一个封装好的模块
    ​ 要学习的就是模块的使用方法 
     

    1.2socket的发展 

    ​ 最开始socket使用来完成进程间通讯的,并不是用来网络通讯,那时候还没有网络
    ​ 后来有了网络之后 .基于之前的socket来进行了更新  使其可以支持网络通讯
    ​ 所以socket分为两种类型 
    ​ AF_UNIX : 进程间通讯
    ​ AF_INET : 网络通讯  
     

    1.3 socket在OSI中的位置

    案例说明:

      socket客户端.py

    import socket

    1.# 买个电话
    client = socket.socket()

    # 作为客户端 ip和端口可以变化 所有系统会自动分配随机端给客户端
    client.connect(("127.0.0.1",1688))

    2.# 开始通话
    # 发送数据 注意发送的内容只能是二进制 bytes
    client.send("hello".encode("utf-8"))

    3.# 接收数据 单位为字节
    data = client.recv(1024)
    print(data)

    client.close()
     
     
     

       socket服务器.py

    import socket

    # 作为服务器必明确自己的ip和端口号 并且不应该变化
    # 参数1指定 socket类型AF_INET 表示网络类型
    #参数2指定的传输协议为 SOCK_STREAM表示TCP协议 SOCK_DGRAM UDP协议
    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 1.买电话机

    # 默认就是网络类型 TCP协议
    #server = socket.socket()

    # 127.0.0.1这叫回送地址 表示当前电脑本身
    # ip一定本机ip 本机可能会有多个IP (无线|有限)
    # 注意:需要参数是一个元组 端口就是普通整数
    server.bind(("127.0.0.1",1688)) # 2.插入手机卡

    # 无论是服务器端还是客户端 都是socket 类型

    # 开始监听1688端口 盯着这个端口看以后没有数据过来
    server.listen() # 3.手机开始待机

    # 接收链接请求
    # 第一个是表示客户端的socket 第二个客户端的地址信息
    client,addr = server.accept() # 4.接电话
    # print(type(client))
    # print(addr)


    # 5.收发数据
    data = client.recv(1024)
    print(data)
    client.send("copy!".encode("utf-8"))

    server.close() # 关机
     1.4常见的异常:
     
      1.端口占用问题
    # 如果已经开启了服务器  再次运行将会抛出 端口占用异常  把之前开启的服务器关掉即可
    """
    有些情况   明明已经关闭了进程 但是 还是端口占用 
    可能是进程正在后台运行  可以通过端口查出进程  进行关闭
    windows下
    netstat -ano  | findstr 9898
    tasklist | findstr 进程id    拿到进程名称
    taskkill /f /t /im 进程名称

    大招: 重启电脑
     
    案例:说明
    import socket
    server = socket.socket()

    server.bind(("127.0.0.1",9891))
    server.listen()
    server.accept()

    server.close()


    # 如果已经开启了服务器 再次运行将会抛出 端口占用异常 把之前开启的服务器关掉即可
    """
    有些情况 明明已经关闭了进程 但是 还是端口占用
    可能是进程正在后台运行 可以通过端口查出进程 进行关闭
    windows下
    netstat -ano | findstr 9898
    tasklist | findstr 进程id 拿到进程名称
    taskkill /f /t /im 进程名称

    大招: 重启电脑
    """

         2.常见异常实例

    服务器.py
    import socket

    server = socket.socket()

    server.bind(("127.0.0.1",8888)) # 只有服务器需要绑定

    server.listen()

    # accept 是一个阻塞函数 会一直等到有客户端链接过来 在继续执行
    client,addr = server.accept() # 完成了三次握手
    # print(client)
    # print(addr)

    print("握手成功!")
    # 收发数据 注意都是用表示客户端的socket来收发数据
    # client.send("world".encode("utf-8"))

    import time
    time.sleep(3)
    try:
    # data = client.recv(1024)
    # print("客户端发来的数据:", data)
    # 发送数据时 对方可能也会异常下线 也会抛出异常
    # 接收数据 和发送数据都应该放到try
    client.send("test".encode("utf-8"))

    except:
    print("client 下线了")
    # 断开链接
    client.close() # 完成四次挥手


    server.close()
    print("服务器关机!")
     
    客户端.py
    import socket

    client = socket.socket()

    # connect本质实在进行三次握手 也是一个数据传输的过程 如果服务器没有立马响应 也会阻塞
    #
    client.connect(("127.0.0.1",8888)) # 三次握手
    print("握手成功! client")


    # 发送数据 本质上是把数据交给操作系统来进行发送 一旦数据交给了操作系统 后续的发送
    # 应用程序就无法控制了 ,send一般不会卡 当然 如果数据量很大就会阻塞
    # client.send("hello".encode("utf-8"))
    # print("发送完成")

    # 是从操作系统缓存区读取数据 如果当前还没有任何数据 就会进入阻塞
    # 会一直等到有数据到来 再继续执行
    # try:
    # data = client.recv(1024)
    # print("接收完成!")
    # print(data)
    # except:
    # print("服务器 强行下线了!")


    import time
    time.sleep(10)
    # 客户端执行close 是正常关闭链接 会给服务器送空字节 用于表示要断开链接
    client.close()
    print("关机了!")


    1.5加上循环
    服务器.py
    import socket
    server = socket.socket()
    server.bind(("127.0.0.1",8989))
    server.listen()

    while True:
    client_socket,client_addr = server.accept()
    buffer_size = 1024 #缓冲区  就是一个临时的容器  
    # 缓冲区大小 不能随便写 太大会导致内存溢出 太小效率低 在内存能够承受的情况下 大一些

    while True:
    try:
    data = client_socket.recv(1024)
    # 在linux中 对方如果强行下线了 服务器不会抛出异常 只会收到空消息
    # 得加上判断 如果为空则意味着 对方下线了 应该关闭链接 跳出循环
    # windows上正常关闭 也会收到空消息 if 必须要加
    if not data:
    client_socket.close()
    break

    print(data.decode("utf-8")) # 解码时必须保证双方同意编码方式
    # 转为大写在发回去
    client_socket.send(data.upper())
    except ConnectionResetError as e:
    print("%s %s" % (client_addr[0],client_addr[1]),e)
    # 如果对方下线了 那服务器也应该关闭对应的客户端对象
    client_socket.close()
    break


    # 通常服务器不会关闭
    # server.close()

    客户端.py
    import socket

    client = socket.socket()
    # 指定服务器的端口和ip 客户端的端口系统自动分配的
    client.connect(("127.0.0.1",8989)) #


    # 添加循环 用来重复收发数据
    while True:
    # 收发的顺序 必须很对面相反 否则卡死了
    msg = input("输入内容:")
    if not msg:continue
    client.send(msg.encode("utf-8"))
    print("sended!")
    data = client.recv(1024)
    print(data.decode("utf-8"))


    client.close()
    1.6window正常结束

    服务器.py
    import socket
    server = socket.socket()
    server.bind(("127.0.0.1",8989))
    server.listen()

    while True:
    client_socket,client_addr = server.accept()
    buffer_size = 1024 #缓冲区  就是一个临时的容器  
    # 缓冲区大小 不能随便写 太大会导致内存溢出 太小效率低 在内存能够承受的情况下 大一些

    while True:
    try:
    data = client_socket.recv(1024)
    # 在linux中 对方如果强行下线了 服务器不会抛出异常 只会收到空消息
    # 得加上判断 如果为空则意味着 对方下线了 应该关闭链接 跳出循环
    if not data:
    client_socket.close()
    break

    print("收到数据:",data.decode("utf-8")) # 解码时必须保证双方同意编码方式
    # 转为大写在发回去
    client_socket.send(data.upper())
    except ConnectionResetError as e:
    print("%s %s" % (client_addr[0],client_addr[1]),e)
    # 如果对方下线了 那服务器也应该关闭对应的客户端对象
    client_socket.close()
    break


    # 通常服务器不会关闭
    # server.close()

    客户端.py
    import socket

    client = socket.socket()
    # 指定服务器的端口和ip 客户端的端口系统自动分配的
    client.connect(("127.0.0.1",8989)) #


    # 添加循环 用来重复收发数据
    while True:
    # 收发的顺序 必须很对面相反 否则卡死了
    msg = input("输入内容:(q:退出)")
    if msg == "q":break
    if not msg:continue
    client.send(msg.encode("utf-8"))
    print("sended!")
    data = client.recv(1024)
    print(data.decode("utf-8"))

    client.close()
     
    ​ 
     
     
     
     
     
     
     
     
     
     
    ​  
    ​ 
    ​ 
    ​ 
        ​ 
       
       
        ​ 
        ​ 
       
       
       
       
       
        
       
       
       
       
       
        ​ 
        ​ 
       
        ​ 
       
       
       
       
       
       
           
        ​ 
       
        ​ 
       
       
       
       
       
       
       
       
       
       
       
       
       
        ​ 
        ​ 
       
       
       
       
       
       
       
       
       
       
     
     
    ​ 
    ​ 
     
     
     
     
     
    ​  
     
     
     
    ​ 
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    MVC 4 中 WEB API 选择 返回格式
    用XML配置菜单的一种思路,附一些不太准确的测试代码
    2020.11.15(每周总结)
    2020.11.19
    2020.11.22
    2020.11.21
    2020.11.14
    202.11.13
    2020.11.20
    2020.11.17
  • 原文地址:https://www.cnblogs.com/llx--20190411/p/10937340.html
Copyright © 2011-2022 走看看