• 网络编程笔记


    网络编程

    网路编程基础知识

    1. C/S和B/S架构

      C : client S : server 客户端,服务端

      B : browser S : server 浏览器,服务端

      B/S架构本质也是C/S

    2. 网络的七层协议:(应表会传网数物)

      • 物理层:电信号(0和1)

      • 数据链路层:把物理层的电信号分组,每一组叫一个数据报数据帧,每一帧有:报头head和数据data两部分。

        头固定18字节:6:发送者地址/6:接收者地址/6:数据类型

      • 网络层:

        • ip:ipv4:32位2进制表示:点分十进制表示

        • 子网掩码:通过子网掩码和ip判断两个ip是否处于同一个网段,通过ip地址和子网掩码做按位与运算

          ip地址: 172.16.10.1: 10101100.00010000.00001010.000000001
          子网掩码:255.255.255.0: 11111111.11111111.11111111.000000000
          按位与运算:172.16.10.0 10101100.00010000.00001010.000000000

        • ip和mac有转换关系:主要是因为ARP协议mac地址学习

      • 传输层:

        • tcp协议:

          • 三次握手、四次挥手
          • dos和ddos攻击:拒接服务攻击,分布式的拒接服务攻击
          • 端口号:0—65535,0—1023为系统占用端口
        • udp协议:

          直接发送,不需要响应,所以数据不可靠。(看视频花屏)

        • 端口:

          • 通过ip + 子网掩码确定一台设备
          • 通过ip + 子网掩码 + 端口号确定一个软件
      • 会话层:使应用建立和维持会话,并能使会话获得同步。

      • 表示层:作用之一是为异种机通信提供一种公共语言,以便能进行互操作。

      • 应用层:应用层向应用程序提供服务,这些服务按其向应用程序提供的特性分成组,并称为服务元素。

    网络编程常用模块

    模块 描述
    socket 基于传输层TCP、UDP协议进行网络编程的模块
    asyncore socket模块的异步版,支持基于传输层协议的异步通信
    asynchat asyncore的增强版
    cgi 基本的CGI(Common Gateway Interface,早期开发动态网站的技术)支持
    email E-mail 和 MIME消息处理模块
    ftplib 支持FTP协议的客户端模块
    httplib、http.client 支持HTTP协议以及HTTP客户端模块
    imaplib 支持IMAP4协议的客户端模块
    mailbox 操作不同格式邮箱的模块
    mailcap 支持Mailcap文件处理的模块
    nntplib 支持NTTP协议的客户端模块
    smtplib 支持SMTP协议(发送邮件)的客户端模块
    poplib 支持POP3协议的客户端模块
    telnetlib 支持TELNET协议的客户端模块
    urllib 支持URL处理的模块
    xmlrpc 支持XML-RPC协议的服务器和客户端模块

    接下来我们会主要讨论socket模块

    socket模块

    程序再使用socket之前,必须先创建socket对象,可以通过以下语法创建socket实例:

    s = socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
    
    • family 参数用于指定网络类型。总共有三个值:AF_INET(基于IPv4协议的网络)、AF_INET6(基于IPv6协议的网络)、AF_UNIX(UNIX网络)
    • type 参数用于指定网络Sock类型。默认是SOCK_STREAM(基于TCP协议的socket)、SOCK_DGRAM(基于UDP协议的socket)、SOCK_RAM(原始socket)
    • 后两个可以忽略

    那么创好socket对象后就需要区分服务端和客户端了。

    socket对象方法

    作为服务器端使用的socket必须绑定到指定IP地址和端口,并在该IP地址和端口进行监听,接收来自客户端的连接。

    socket对象提供了如下常用方法:

    • bind(address):作为服务端使用的socket调用该方法,将socket绑定到指定address元组(IP, 端口)。
    • listen([backlog]):服务端的监听方法。
    • accept() :服务端接收来自客户端的连接。
    • recv(bufsize[,flags]):接收socket中的数据(bytes)。
    • recvfrom(bufsize[,flags]):与上方法类似,返回(bytes, address)元组。
    • send(bytes[, flags]):向socket发送数据(必须已经建立连接),通常用于基于TCP协议的网络。
    • sendto(bytes, address):用于UDP协议网络中发送数据
    • sendfile(file, offset=0, count=None):将整个文件内容都发过去。
    • connect(address):客服端连接服务器。
    • connect_ex(address):与上方法大致相同,只是程序出错时不会抛出异常,而是返回一个错误标识。
    • close():关闭连接,回收资源。

    使用socket通信(TCP)

    • 服务端:

      import socket
      
      host = socket.gethostname()  # 获取本机host
      server = socket.socket()
      
      server.bind((host,8080))
      server.listen(5)
      
      while 1:
          c, addr = server.accept()  # 与客户端建立连接
          c.send(b"start:")
      
          while 1:
              '''通信循环,try为了等待客户端断开后连接其他的客户端'''
              try:
                  print(f"	33[1;36m{c.recv(1024).decode()}33[0m")
                  msg = input(">>").encode('utf-8')
                  c.send(msg)
              except Exception:
                  print("客户端断开连接了!")
                  break
      
    • 客户端:

      import socket
      
      host = socket.gethostname()  # 获取本机host
      cilent = socket.socket()
      cilent.connect((host, 8080))
      
      while 1:
          '''通讯循环'''
          print(f"	33[1;36m{cilent.recv(1024).decode()}33[0m")
          msg = input(">>").encode('utf-8')
          cilent.send(msg)
      

    粘包问题

    TCP协议中的数据都是以数据流(type=SOCK_STREAM)的形式传递的,很容易发生几次send的数据被一次recv(接收),或者被截成了好几段。为了解决粘包问题,我们借用了数据报的思想,给每一条数据加一个固定长度的头。这里引入struct模块来创建固定的头。

    示例:写一个仿SHH的客户端和服务端

    • 服务端

      import socket
      import subprocess
      import struct
      
      server = socket.socket()
      host = socket.gethostname()
      port = 8081
      
      server.bind((host, port))
      server.listen(5)
      
      while 1:
          c, addr = server.accept()
          print(addr, "连接了 >>>")
          msg = b"hello "
          le = struct.pack('i',len(msg))  # 将要发送的数据的长度封装成固定长度为4的二进制数据
          c.send(le)  # 先发送一个头
          c.send(msg) # 再发送数据
          try:
              while 1:
                  ssh = c.recv(1024)
                  obj = subprocess.Popen(ssh.decode('gbk'), shell=True, stdout=subprocess.PIPE , stderr=subprocess.PIPE)
                  # subprocess是与系统交互的模块
                  msg = obj.stdout.read() or obj.stderr.read()  # 必然拿到其中一项
                  le = struct.pack('i',len(msg))  # 将结果打上头
                  c.send(le)  # 与上一样
                  c.send(msg)
          except Exception:
              print(" 断开连接 !")
      
    • 客户端

      import socket
      import struct
      
      client = socket.socket()
      host = socket.gethostname()
      port = 8081
      
      client.connect((host,port))
      
      while 1:
          le = struct.unpack('i', client.recv(4))[0] # 解析头,获取数据长度
          print(client.recv(le).decode('gbk'))  # shell只接收gbk编码
          ssh = input(" 请输入命令 >>")
          client.send(ssh.encode('gbk'))  # 返回执行结果
      

    socketserver模块

    socketserver模块实现了多线程通信。使用socketserver创建服务端:

    #使用socketserver写服务端
    import socketserver
    
    #自己定义一个类,必须继承StreamRequestHandler或BaseRequestHandler
    class MyTcp(socketserver.StreamRequestHandler):
        #必须重写handle方法
        def handle(self):
            '''这是服务端与客户端交互的方法'''
            try:
                while True :  #通信循环
                    # print(self)
                    #给客户端回消息
                    #conn对象就是request
                    #接收数据
                    print(self.client_address)
                    data=self.request.recv(1024)
                    print(data)
                    if len(data)==0:
                        return
                    #发送数据
                    self.request.send(data.upper())
            except Exception:
                pass
            
    if __name__ == '__main__':
        #实例化得到一个tcp连接的对象,Threading意思是说,只要来了请求,它自动的开线程来处理连接跟交互数据
        #第一个参数是绑定的地址,第二个参数传一个类
        server=socketserver.ThreadingTCPServer(('127.0.0.1',8009),MyTcp)
        #一直在监听
        #这么理解:只要来一个请求,就起一个线程交互
        server.serve_forever()
    
  • 相关阅读:
    BZOJ2330 SCOI2011糖果
    BZOJ 3812主旋律
    模板更新 扩展卢卡斯
    BZOJ4556 HEOI2016字符串
    CodeForces700E Cool Slogans
    Atcoder Contest069F:Flag
    计算几何模板(更新中......)
    BZOJ4003 JLOI2015城池攻占
    BZOJ3772精神污染
    HDU5919 SequenceⅡ
  • 原文地址:https://www.cnblogs.com/Du704/p/11569558.html
Copyright © 2020-2023  润新知