Python 网络编程

网络

  • 理论模型,分为七层

    • 物理层
    • 数据链路层
    • 传输层
    • 会话层
    • 表示层
    • 应用层
  • 实际应用,分为四层

    • 链路层
    • 网络层
    • 传输层
    • 应用层
  • IP地址

    • IPV4 地址族,4个字段组成,每个字段取值0-255

      • 局域网IP,192.168.XXX,XXX

      • 本机本地地址,127.0.0.1

    • IPV6 地址族,8个字段组成,每个字段取值0000-FFFF

  • 端口

    • 设备上每个应用需要与外界通信的地址

    • 范围是 0-65535

    • 知名端口 0-1023

    • 非知名端口 1024-65535

  • 套接字

    • 我理解的套接字相当于与电话,而人则代表每个设备;当两个人需要通信时,需要电话.这就是套接字,而知道电话是不够的,还需要知道电话号码,这样才能确保电话打到你想通话的哪个人去

    • 套接字对象由addr(host,port)地址定义,host是IP地址,port代表端口

    • host主要用来确定是IP地址为哪一个的电脑

    • port主要用来确定是该电脑上的哪个软件

  • 域名

    • 网络上计算名,或计算机组的名称

    • 浏览器根据域名来查找对应的IP地址

      • 查找本地hsot文件,检查是否有对应的IP地址

      • 如果没有,查找本地DNS服务器.也就是运营商,检查是否有对应的IP

      • 如果没有,本地DNS服务器查找根DNS服务器,检查是否有对应的IP

      • 如果没有,根DNS服务器返回消息给本地DNS服务器,让其到域服务器查找IP

  • DNS 域名服务器系统

    • DNS将域名映射到对应的IP地址

    • DNS查询

      • 递归查询

      • 迭代查询

    • DNS 负载均衡

      • 在DNS服务器中,为域名配置多个IP地址,根据距离远近,使用距离较近的IP

socket 库

  • 协议家族

    • 基于文件

      • AF_UNIX 同台机器进程之间的通行
    • 基于网络

      • AF__INET IPV4协议

      • AF_INET6 IPV6协议

  • 网络协议

    • SOCK_STREAM TCP协议 , 连接的套接字,只有当服务器与客户端连接后,才开始传输数据,可以确定数据的先后,也可以确定对方一定能接收到消息

    • SOCK_DGRAM UDP协议 , 无连接的套接字,服务器不断的监听某个套接字,从这个套接字获取或者发送数据,无法确定数据的先后顺序,也无法确定对方是否收到消息

  • 直接调用的函数

    • getfqdn(name) 返回name的域名

    • gethostbyname(hostname) 返回主机名的IPV4地址

    • gethostname() 返回正在执行当前解释器的机器的主机名

    • sethostname(name) 将本机主机名设置为name

  • socket(family,type) 套接字对象类

    • 函数

      • 通用函数

        • bind(addr) 服务器绑定套接字,addr为(host,port)

        • shuntdown() 关闭连接

        • setblocking(boolean) 设置是否为阻塞模式

        • settimeout(second) 设置超时时间

          • None 阻塞模式
          • 0 非阻塞模式
          • 非0值 在规定时间后抛出异常
        • close() 关闭套接字

      • TCP 函数

        • listen() 监听地址,阻塞式的,不断循环监听地址

        • accept() 服务器接收TCP客户端连接,返回新的连接的套接字和客户端的地址

        • send(data) 发送数据

        • sendall(data) 发送所有数据

        • recv(bufsize) 接收TCP指定字节数的数据,一旦超过指定字节,就需要使用循环接收的方式接收完整的数据

          • 短链接法,发送数据完毕后关闭连接,让recv()函数获取连接关闭后自动取消阻塞模式

          • 末尾标志法,在末尾添加相应哨兵值,在recv()函数接收到哨兵值之后跳出接收数据的死循环,进行下一步操作

          • 负载长度法,提前告知长度,后根据长度判断是否跳出接收数据的死循环

        • connect(addr) 发起连接,向addr(host,port)发起连接

        
        # 设置TCP服务器
        
        import socket,time
        
        server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        
        server.bind(('127.0.0.1',12345))
        
        server.listen()
        
        con,addr = server.accept()
        
        data = con.recv(1024)
        
        text = data.decode()
        print(text)
        
        data = '{0} : {1}'.format(time.ctime(),text).encode()
        
        con.sendall(data)
        
        con.close()
        
        server.close()
        
        
        # 设置TCP客户端
        
        import socket
        
        client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        
        client.connect(('127.0.0.1',12345))
        
        text = 'Hello'
        
        client.sendall(text.encode())
        
        data = client.recv(1024)
        
        print(data.decode())
        
        client.close()
      • UDP 函数

        • recvfrom(bufsize) 接收UDP消息,返回连接的套接字地址

        • sendto(data,addr) 将data数据发送到指定addr地址

        
        # 设置UDP服务器
        
        import socket,time
        
        server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
        
        server.bind(('127.0.0.1',12345))
        
        data,addr = server.recvfrom(1024)
        
        text = data.decode()
        print(text)
        
        server.sendto('{0} : {1}'.format(time.ctime(),text).encode(),addr)
        
        server.close()
        
        
        # 设置UDP客户端
        
        import socket
        
        client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
        
        text = 'Hello'
        
        client.sendto(text.encode(),('127.0.0.1',12345))
        
        data,addr = client.recvfrom(1024)
        
        print(data.decode())

socketserver 网络服务器框架模块

  • 此模块提供网络服务器框架,可以使开发者更加快捷的开发出相应的网络服务器

  • 服务器server对象

    • BaseServer(server_address,RequestHandlerClass) 所有Server对象的超类,同步处理请求,只有当一个请求处理完成之后才能处理下一个请求,每次只能完成一个请求

      • RequestHandlerClass 处理请求类

      • get_request() 接收客户端请求,并返回一个和客户端连接的套接字和客户端地址组成的元组

      • server_bind(addr) 绑定地址

      • serve_forever() 永远处理请求

      • shutdown() 停止处理请求

      • server_close() 关闭服务器

    • TCPServer (server_address,RequestHandlerClass) 继承于BaseServer,完善了TCP的相关方法,用于TCP服务器的创建,需要重写RequestHandlerClass

    
    # 改写的上面采用socket库编写的TCP服务器
    
    import socketserver,time
    
    class Server(socketserver.TCPServer):
        pass
    
    class MyRequestHandler(socketserver.StreamRequestHandler):
    
        def handle(self):
            data = self.request.recv(1024)
            text = data.decode()
            print(text)
            data = '{0} : {1}'.format(time.ctime(),text).encode()
            self.request.sendall(data)
    
    server = Server(('127.0.0.1',12345),MyRequestHandler)
    server.serve_forever()
    
    
    # 客户端
    
    import socket
    
    with socket.socket(socket.AF_INET,socket.SOCK_STREAM)as client:
    
        client.connect(('127.0.0.1',12345))
    
        client.sendall('hello'.encode())
    
        data = client.recv(1024)
    
        print(data.decode())
    • UDPServer (server_address,RequestHandlerClass) 继承于BaseServer,完善了TCP的相关方法,用于UDP服务器的创建,需要重写RequestHandlerClass
    
    # 服务器端
    
    import socketserver,time
    
    class Server(socketserver.UDPServer):
        pass
    
    class MyRequestHandler(socketserver.DatagramRequestHandler):
    
        def handle(self):
            data,con = self.request
            print(data.decode())
    
            data = '{0} : {1}'.format(time.ctime(),data.decode()).encode()
            con.sendto(data,self.client_address)
    
    server = Server(('127.0.0.1',12345),MyRequestHandler)
    server.serve_forever()
    
    
    # 客户端
    
    import socket
    
    with socket.socket(socket.AF_INET,socket.SOCK_DGRAM)as client:
    
        data = 'hello'.encode()
        client.sendto(data,('127.0.0.1',12345))
    
        data = client.recv(1024)
        print(data.decode())
    • 适用于Unix平台的服务器,

      • UnixStreamServer (server_address,RequestHandlerClass)

      • UnixDatagramServer (server_address,RequestHandlerClass)

  • 扩展功能的Mixin类

    • ForkingMixIn 多进程MIXIN类 ,可以与其他Server对象进行组合,适用于Linux 平台

    • ThreadingMixIn 多线程MIXIN类,可以与其他Server对象进行组合

  • 模块中已组合的扩展功能的服务器Server类

    • ForkingTCPServer(server_address,RequestHandlerClass) 多进程TCP服务器类,ForkingMixIn与TCPServer的组合

    • ForkingUDPServer(server_address,RequestHandlerClass) 多进程UDP服务器类,ForkingMixIn与UDPServer的组合

    • ThreadingTCPServer(server_address,RequestHandlerClass) 多线程TCP服务器类,ThreadingMixIn与TCPServer的组合

    • ThreadingUDPServer(server_address,RequestHandlerClass) 多线程UDP服务器类,ThreadingMixIn与UDPServer的组合

  • 请求处理类

    • BaseRequestHandler 处理请求类,其中定义了三个方法:setuphandlefinish,都默认什么都不做,需要进行重写才能使用,是其他处理请求类的超类

      • setup() 在handle方法之前调用的操作

      • handle() 处理客户端请求的方法

        • self.request 在不同Server服务器对象中具有不同的含义

          • 在TCPServer中,返回的是连接的客户端的套接字

          • 在UDPServer中,返回的数据和连接的客户端套接字的一个元组

        • self.client_address 返回连接的客户端的地址

        • self.rfile 可以从此属性中读取客户端发送的数据

        • self.wfile 可以从此属性中写入服务器发给客户端的数据

      • finish() 在handle方法之后调用的操作

    • StreamRequestHandler TCP处理请求类,是BaseRequestHandler的子类,实现了关于TCP的相关方法,但需要实现handle方法

    • DatagramRequestHandler UDP处理请求类,是BaseRequestHandler的子类,实现了关于UDP的相关方法,但需要实现handle方法

ftplib 模块

  • FTP (FileTransferProtocal) 文件传输协议

  • 用户

    • Real账户 注册账户

    • Guest账户 临时账户

    • Anonymous 匿名账户

  • 端口

    • 21 端口为控制和命令端口

    • 20 端口为数据端口

  • FTP(host,usr,passwd)类

    • 可以使用上下文管理协议 即with语句

    • connect(host,port) 当没有在实例化FTP定义host时,则需要调用connect函数指定host和port

    • login(usr,passwd) 给定账号密码登录,默认usr为anonymous,密码为anonymous@

    • abort() 中断传输的文件

    • sendcmd(cmd) 向服务器发送字符串命令,并返回响应代码

    • retrbinary(cmd,callback) 以二进制形式接收文件,callback为用于接收文件的回调函数

    • storbinary(cmd,fp) 以二进制形式上传文件,fp为二进制流

    • retrlines(cmd,callback) 文本形式接收文件

    • storlines(cmd,fp) 文本形式上传文件

    • nlst() 返回文件名列表

    • dir() 输出文件名列表到sys.stdout

    • rename(old,new) 重命名

    • delete(filename) 删除文件

    • pwd() 返回当前目录路径

    • cwd(path) 将path设置为当前路径

    • mkd(path) 创建新目录

    • rmd(dirname) 删除dirname目录

    • size(file) 返回文件大小

    • quit() 关闭连接

import ftplib

#定义回调函数,将retrbinary函数接收到的数据写入本地文件中
def file(data):
    with open(r'1.txt','wb')as f:
        f.write(data)

# 指定FTP的host,获得套接字连接
con = ftplib.FTP('ftp.acc.umu.se')

# 连接FTP服务器
con.connect()

# 匿名账户登录
con.login()

con.dir()

# 下载文件,并调用file函数,将数据写入本地文件
con.retrbinary('RETR robots.txt',file)

# 关闭连接
con.close()

email 电子邮件模块

  • 邮件传输模式

    • MUA 客户端程序

    • MTA (Mail Transfer Agent) 邮件传输代理,将发件人的邮件传输到发件人邮箱所在的服务器

    • MDA (Mail Delivery Agent) 邮件投递代理,发件人邮箱所在的服务器将邮件传输到收件人邮箱所在的服务器

    • MRA (Mail retrieva Agent) 邮件获取代理,收件人邮箱所在的服务器将邮件获取到收件人的邮箱地址中去

  • 邮件传输使用MIME协议(多用途互联网邮件扩展),即电子邮件需要符合相应的MIME格式,才能进行发送

    • MIME协议中包括邮件标头、邮件消息体两个部分

    • 邮件标头是key-value形式的字符串,每个标头独占一行

    • 标头属性

      • From 发件人地址
      • To 收件人地址
      • Cc 抄送地址
      • Subject 主题
      • Content-Type 邮件体中包含的内容类型
      • Content-Disposition: "attachment;filename='name.type'" 设置附件的下载方式和显示名称,其中attachment为附件方式打开,inline在邮件中打开
    • 标头后跟着空行,下面为邮件消息体

    • 消息体为邮件的具体内容

Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
From: mine
To: you
Subject: =?utf-8?b?6YKu5Lu25qCH6aKY?=

6L+Z5piv5LiA5Lu95paH5pys5raI5oGv6YKu5Lu2
  • mime 构造邮件消息模块

    • 每个MIME类型的邮件消息对象只需要添加标头就可以作为邮件进行发送

    • multipart.MIMEMultipart(subtype ='mixed',boundary = None,spartparts = None,policy = compat32) 构造多个消息组成的总消息

    • application.MIMEApplication(data,subtype = '八位字节流',encoder = email.encoders.encode_base64) 构造MIME邮件的Application消息

    • audio.MIMEAudio(audiodata,subtype = None,encoder = email.encoders.encode_base64) 构造MIME邮件的Audio消息

    • image.MIMEImage(imagedata,subtype = None,encoder = email.encoders.encode_base64) 构造MIME邮件的Image消息

    • text.MIMEText(text,subtype ='plain',charset = None,*,policy = compat32) 构造一个MIME邮件的文本消息

  • message 邮件消息操作模块

    • EmailMessage

      • 同下
    • Message

      • as_string() 将消息对象作为字符串返回

      • as_bytes() 将消息对象作为二进制流返回

      • attach(message) 将message消息对象添加到当前消息对象

      • items() 返回消息字段标题和值的元组的列表

      • add_header(name,value) 添加邮件标头

      • get_payload(i=None, decode=False) 返回邮件消息中每行内容所组成的列表,选择是否解码,一般需要填入True

      • walk() 迭代器,迭代邮件消息的每一行

  • header 构造邮件标头模块

    • Header(str=None,charset=None,header_name = NONE) 类 创建符合MIME协议的标头

    • 邮件标头可以通过两种方式进行构造

      1. 使用Header类进行构造,使用消息对象的属性进行赋值
      msg['From'] = Header('[email protected]') 
      1. add_header(name,value)函数,使用消息对象的函数进行赋值
      msg.add_header('From','[email protected]')
    • 邮件头的解码

      • decode_header(_header) 解码标头值,返回(decode_string,charset)组成的元组的列表
  • parse 邮件解码模块

    • BytesParser 二进制数据解析类

      • parse(fp,headersonly = False ) 解析二进制流,生成消息对象

      • parsebytes(bytes,headersonly = False ) 解析二进制数据,生成消息对象

      • BytesHeaderParser() 解析标头二进制数据,返回标头对象

    • Parser 文本解析类

      • parse(fp,headersonly = False ) 解析文本流,生成消息对象

      • parsestr(text,headersonly = False ) 解析字符串,生成消息对象

      • HeaderParser() 解析标头文本数据,返回标头对象

  • email模块下直接使用的解析类

    • message_from_bytes(s,_class = None,*,policy = policy.compat32 ) 从二进制数据返回消息对象

    • message_from_binary_file(fp,_class = None,*,policy = policy.compat32 ) 从二进制流返回消息对象

    • message_from_string(s,_class = None,*,policy = policy.compat32 ) 从字符串返回消息对象

    • message_from_file(fp,_class = None,*,policy = policy.compat32 ) 从文本流中返回消息对象

smtplib SMTP简单邮件发送协议模块

  • SMTP 是负责邮件发送的协议

  • SMTP(host,port) 未加密的SMTP类

    • 可以使用上下文管理协议,即with语句

    • connect(host,port) 连接到邮件服务器

    • login(usr,pwd) 登录

    • sendmail(from_addr,to_addr,msg) 发送邮件 msg为字符串,也就是需要通过消息对象调用as_string()方法

    • quit() 关闭连接

  • SMTP_SSL(host,port) ssl加密的SMTP类

    • 方法同上
  • 发送一封纯文本格式的邮件

    import smtplib
    from email.mime.text import MIMEText
    
    usr = '[email protected]'
    pwd = 'xxxxx'
    to_mail = '[email protected]'
    
    
    # 构造文本消息邮件
    
    msg = MIMEText('这是一份文本消息邮件')
    
    
    # 添加标头,使之变为邮件
    
    msg['From'] = 'mine<{0}>'.format(usr)
    msg['To'] ='you<{0}>'.format(to_mail)
    msg['Subject'] = '邮件标题'
    
    
    # 发送邮件
    
    with smtplib.SMTP()as con:
    
        # 变为debug模式,输出信息到控制台
        con.set_debuglevel(1)
    
        # 连接邮件服务器
        con.connect('smtp.163.com',25)
    
        # 登录
        con.login(usr,pwd)
    
        # 发送邮件
        con.sendmail(usr,to_mail,msg.as_string()) 
  • 发送一封html格式的邮件

    import smtplib
    from email.mime.text import MIMEText
    
    usr = '[email protected]'
    pwd = 'xxxxx'
    to_mail = '[email protected]'
    
    
    # 构造html
    
    content ="

    这是一封html邮件

    "
    # 构造文本消息邮件 msg = MIMEText(content,'html','utf-8') # 添加标头,使之变为邮件 msg['From'] = 'mine<{0}>'.format(usr) msg['To'] ='you<{0}>'.format(to_mail) msg['Subject'] = '邮件标题' # 发送邮件 with smtplib.SMTP()as con: # 变为debug模式,输出信息到控制台 con.set_debuglevel(1) # 连接邮件服务器 con.connect('smtp.163.com', 25) # 登录 con.login(usr, pwd) # 发送邮件 con.sendmail(usr, to_mail, msg.as_string())
  • 发送一封带有附件的邮件

    import smtplib
    from email.mime.multipart import MIMEMultipart
    from email.mime.application import MIMEApplication
    from email.mime.text import MIMEText
    
    usr = '[email protected]'
    pwd = 'xxxxx'
    to_mail = '[email protected]'
    file = r'C:\Users\wudiz\Desktop\BaseServer.png'
    
    
    # 构造文本消息邮件
    
    msg = MIMEMultipart('组合邮件')
    
    
    # 添加标头,使之变为邮件
    
    msg['From'] = 'mine<{0}>'.format(usr)
    msg['To'] ='you<{0}>'.format(to_mail)
    msg['Subject'] = '邮件标题'
    
    
    # 构造文本
    
    text = MIMEText('这是一封组合邮件')
    
    
    # 添加到msg组合消息对象中
    
    msg.attach(text)
    
    
    # 构造附件
    
    data = MIMEApplication(open(file,'rb').read())
    
    
    # 添加MIME类型
    
    data.add_header('Content-Type','application/octet-stream')
    
    
    # 设置附件
    
    data.add_header('Content-Disposition',"attachment;filename='1.png'")
    
    
    # 添加到msg组合消息对象中
    
    msg.attach(data)
    
    
    # 发送邮件
    
    with smtplib.SMTP()as con:
    
        # 变为debug模式,输出信息到控制台
        con.set_debuglevel(1)
    
        # 连接邮件服务器
        con.connect('smtp.163.com', 25)
    
        # 登录
        con.login(usr, pwd)
    
        # 发送邮件
        con.sendmail(usr, to_mail, msg.as_string())

poplib 邮局协议模块

  • POP3 (Post Office Protocol - Version 3) 邮局协议版本3

  • POP3(host,port) 非加密POP3协议类

    • set_debuglevel(1) 设置为调试模式

    • stls() 以tls验证服务器

    • getwelcome() 返回服务器的问候语字符串

    • capa() 查询服务器的功能

    • user(usr) 发送用户名

    • pass_(pwd) 发送密码

    • apop(usr,pwd) 使用APOP身份验证登录邮箱

    • rpop(usr,pwd) 使用RPOP身份验证登录邮箱

    • stat() 获取邮箱状态,返回(message_count,mailbox_size)的元组

    • list(num) 获取邮件列表,如果设置了数字,则为数字所在编号邮件的内容,返回(response,num,octets)组成的元组 response为响应代码,num为邮件数量,octets为邮件大小

    • retr(num) 检索邮件号,返回(response,lines,octets)组成的元组 lines为邮件每行组成的一个二进制列表,需要将其每个一行的组合起来才能变成二进制邮件,二进制邮件解码才能变为邮件

    • dele(num) 标记邮件号,退出登录后删除

    • rset() 立即删除标记的邮件号

    • quit() 关闭连接

  • POP3_SSL(host,port) SSL加密POP3协议类

    • 方法同上,现在一般使用该类
    import poplib
    import email.header
    
    
    # 指定连接POP3服务器的host和port
    
    con = poplib.POP3('pop3.163.com',110)
    
    con.set_debuglevel(1)
    
    con.user('xxx')
    
    con.pass_('xxx')
    
    print(con.getwelcome())
    
    
    # 选定邮箱中的第三封邮件
    
    list = con.retr(3)
    
    
    # 设置二进制对象
    
    data = b''
    
    
    # 将二进制邮件的每一行写入data中,构建完整的邮件,按每行进行写入
    
    for i in list[1]:
        data = data + i + b'\r\n'
    
    con.quit()
    
    
    # 解析为MIME消息对象
    
    mail = email.message_from_bytes(data)
    
    
    # 解析标头中的标题
    
    subject = email.header.decode_header(mail.get('Subject'))
    
    
    # 解码Subject标头值的字符串,并打印
    
    print(subject[0][0].decode(subject[0][1]))
    
    
    # 按base64解码消息中的内容
    
    content = mail.get_payload(decode=True)
    
    
    # 按UTF-8解码内容
    
    print(content.decode())

http 超文本传输协议模块

  • http协议 是Hyper Text Transfer Protocol的缩写,简称为超文本传输协议

    • HTTP 的默认端口为80

    • HTTPS的默认端口为443

    • 永远是客户端先发起请求,然后服务器响应请求

    • 工作模式

      • 建立连接

        • 需要进行三次握手
          • 客户端发送一个请求给服务端要求建立连接,进入等待状态(SYN_SEND)
          • 服务端同意连接,发送一个响应给客户端,进入等待状态(SYN_SEND)
          • 客户端接收这个响应,并与之建立连接(ESTABLISHED)
      • 接收数据

      • 结束连接

  • 请求报文 Request

    • 请求行包括了请求方法,请求的url和http版本

      • 请求方法

        • POST 向服务器提交数据 改

        • GET 请求数据 查

        • PUT 向服务器上传数据 增

        • DELETE 请求服务器删除相应数据 删

    • 请求头是key-value形式的,其中有以下属性

      • Host 请求资源的主机地址(必须存在)
      • User-Agent 客户端的浏览器类型和版本
      • Accept-Language 客户端申明自己接收的语言
      • Accept 客户端申明自己想要接收数据的类型
        • gzip
        • deflate
      • Accept-Encoding 客户端申明自己接收的编码,通常指定压缩方法
      • Cookie 发送cookie值
      • Connection 连接方式
        • keep-alive 持久连接,当访问网页后连接不会关闭
        • close 短连接,访问后就关闭,下次建立新的连接
      • Keep-Alive 保持连接的时间
      • Referer 表示用户从该网页访问服务器
      • Date 此报文产生的日期
      • Authorization 客户端权限
    • 空行,请求头和请求体之间必须有一个空行

    • 请求体

  • 响应报文 Response

    • 响应行,包括了服务器软件的版本号,返回的状态码和相应短语

      • 1XX 服务器已接收请求,继续处理
      • 2XX 服务器请求已被处理
      • 3XX 重定向
      • 4XX 客户端错误
      • 5XX 服务器错误
    • 响应头

      • Location 重定向到另一个位置
      • Server 服务器软件
      • Date 此报文产生的日期
      • Content-Length 响应体的长度
      • Content-Type 声明发送响应体的类型和编码
    • 空行

    • 响应体,也就是服务器返回的请求资源

  • client HTTP客户端模块模块

    • HTTPConnection(host,port = None) 使用http协议连接服务器,返回一个HTTPConnection对象

      • request(method,url,body = None,headers = {}) 向服务器发送请求

      • getresponse() 返回服务器相应

      • set_debuglevel(1) 设置调试,将输出打印到控制台

      • close() 关闭连接

    • HTTPSConnection(host,port = None) 使用https协议简介服务器,返回一个HTTPSConnection对象

      • 同上
    • HTTPResponse对象

      • read() 读取响应内容

      • getheaders() 返回(属性,值)组成的元组列表

      • getheader(name) 返回属性为name的值

      • version 返回协议版本

      • status 返回状态码

    from http.client import *
    
    con = HTTPConnection('www.baidu.com')
    con.set_debuglevel(1)
    con.request('GET','http://www.baidu.com')
    response = con.getresponse()
    print(response.read())
    response.close()
    con.close()
  • server HTTP服务器模块

    • 服务器框架,此模块继承于socketserver.TCPServer

      • HTTPServer(server_address,RequestHandlerClass )

      • ThreadingHTTPServer(server_address,RequestHandlerClass )

    • 处理HTTP请求类

      • BaseHTTPRequestHandler(request,client_address,server ) 处理http请求的基本类

        • command 请求形式

        • path 请求的url

        • request_version 请求的http版本

        • headers 请求报文的标头

        • rfile 读取流

        • wfile 写入流

        • protocol_version 设置http版本协议

          • 默认为HTTP/1.0 短连接

          • HTTP/1.1 持久连接

        • send_response(code, message=None) 将响应状态码添加到缓冲区

        • send_header(keyword, value) 将响应头添加到缓冲区

        • end_headers() 发送空行

        • version_string() 返回服务器软件的版本号

        • date_time_string() 返回当前时间

        • address_string() 返回呼叫的客户端地址

      
      # 使用BaseHTTPRequestHandler创建HTTP服务器
      
      from http.server import *
      
      html = '''
         
             
              Server   
             
             
              hello Python!
             
      
      '''
      
      class myhttpserver(HTTPServer):
          pass
      
      class myhttphandler(BaseHTTPRequestHandler):
      
          def do_GET(self):
      
              url = self.path
              print(url)
      
              self.send_response(200)
              self.send_header('Hello','from server s welcome')
              self.end_headers()
      
              self.wfile.write(html.encode())
      
      server = myhttpserver(('127.0.0.1',8888),myhttphandler)
      server.serve_forever()
      
      # 现在使用http://127.0.0.1:8888/打开网站吧
      
      • SimpleHTTPRequestHandler(request,client_address,server,directory = None ) 普通HTTP请求处理类

        • 除了和BaseHTTPRequestHandler函数一致时,还另外定义了directory属性,do_HEAD(),do_GET()方法

          • directory 属性: 如果未指定,则代表提供的文件的目录是当前目录

          • do_HEAD() 默认给定Server, Date, Connection, Content-Type, Content-Length, Last-Modified的标头

          • do_GET() 如果代码所在位置有index.html,则会发送这个网页给客户端,否则将建立一个基于当前目录的类似于FTP的服务器

    
    # 类似于FTP服务器
    
    from http.server import *
    
    class myhttpserver(HTTPServer):
        pass
    
    class myhttphandler(SimpleHTTPRequestHandler):
        pass
    
    server = myhttpserver(('127.0.0.1',8888),myhttphandler)
    server.serve_forever()
    
    
    # 使用index.html
    
    
    # 在代码所在目录编写index.html文件
    
    '''
    
    
    
        
        My Page
    
    
        

    Hello Python3!

    '''
    # 再次运行服务器,使用浏览器访问,即可以查看结果
    • CGIHTTPRequestHandler(request,client_address,server ) 调用CGI程序处理请求

      • 修改了SimpleHTTPRequestHandler定义的do_GET和do_HEAD方法,更改为使用CGI程序输出的方法 如果没有CGI程序,就会像SimpleHTTPRequestHandler一样,建立一个类似于FTP的服务器

      • cgi_directories 包含CGI程序的目录,默认为当前目录下的[‘/cgi-bin’, ‘/htbin’]

      • do_POST() 定义了POST方法,允许客户端发送信息到服务器得CGI程序中,如果POST到非CGI程序上,会提示501错误

    
    # 先定义一个能POST请求的html页面,命名为index.html
    
    '''
    
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <h1>请输入文字h1>
        <form action="http://127.0.0.1:8888/cgi-bin/cc.py" method="post" id="myform">
            <p><input type="text" name="text">p>
        form>
        <button type="submit" form="myform">发送button>
    
    body>
    html>
    '''
    
    
    # CGI服务器
    
    from http.server import *
    
    class myhttpserver(HTTPServer):
        pass
    
    class myhttphandler(CGIHTTPRequestHandler):
        pass
    
    server = myhttpserver(('127.0.0.1',8888),myhttphandler)
    server.serve_forever()
    
    
    # 编写CGI程序,放入cgi-bin目录下
    
    import cgi
    import cgitb
    cgitb.enable()
    
    html = '''
    
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <h1>你提交的是:h1>
        <h2>{0}h2>
    body>
    html>
    '''.format(cgi.FieldStorage().getfirst('text'))
    
    print(html)
    
    # 运行程序,会输出你在页面上输入的信息
    
  • cookies HTTP状态管理,主要用于服务器端创建cookie

    • Netscape形式的cookie : Set-Cookie: NAME=VALUE;Expires=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE

      • NAME为该cookie的名称,为必填选项
      • Expires为该cookie的终止日期 形式为星期几,DD-MM-YY HH:MM:SS GMT,GMT表示格林尼治时间,如不填该cookie不会保存在硬盘中,该cookie随着浏览器的关闭消失
      • Domain为该cookie的作用域,如果不填,则为该服务器的域名
      • Path为该服务器下那些页面可以获取该cookie,填’/’为该服务器下所有页面
      • 加密协议,当前只有一种,即HTTPS
    • RFC2109中定义的cookie : Set-Cookie: Name = Value; Comment = value; Domain = value; Max-Age = value; Path = Value;Secure; Version = 1 * DIGIT;

      • NAME必须为一个JSESSIONID,必填
      • Domain为该cookie的作用域,必须以.开始
      • Max-Age为该cookie的生存时间,以秒为单位
      • Secure必填
    • BaseCookie(input) 类

      • 该类用于创建cookie,是一个类似于字典的对象,每向其中添加一个key,value值就会创建一个Set-Cookie: key:value的响应头信息,其中key必须是一个字符串,value是一个Morsel对象,可以向其中添加其他头信息操作

      • 定义的方法:

        • value_decode(val ) 待续
        • value_encode(val ) 待续
        • output(attrs = None,header ='Set-Cookie:',sep ='\ r \ n' ) 将cookie对象作为符合html标准的字符串输出
        • load(rawdata ) 将接收到的字符串对象解析为cookie
    • SimpleCookie(input) 类

      • BaseCookie的子类,重写实现了value_decode,value_encode方法
    • Morsel 类

      • 常用常量

        • expires
        • path
        • comment
        • domain
        • max-age
        • secure
        • version
        • httponly
      • 常用方法

        • set(key,value,coded_value ) 添加key,设置value值
        • output(attrs = None,header ='Set-Cookie:' ) 作为html形式输出
        • update(dict) 将字典中的key和value添加到对象中
# 创建一个cookie,使用了几种不同的方式
from http.cookies import *

cookie = SimpleCookie()

cookie["name"] = "mycookie"

dict = {'path':'/','comment':'这是cookie'}
cookie['name'].update(dict)

cookie['name']['domain'] = '127.0.0.1'

cookie['whatever'] = 'i dont know'

print(cookie)
  • cookiejar 持久化的cookie操作模块,主要用于客户端的操作,如爬虫

    • 具体应用在urllib模块中

    • CookieJar 类,该类用来操作储存在内存中的cookie

      • MozillaCookieJar(filename,delayload = None,policy = None ) 类 可以从加载和保存的Cookie到磁盘Mozilla的cookies.txt

      • LWPCookieJar(filename,delayload = None,policy = None ) 类 可以从加载和cookie保存到磁盘与的libwww-perl的库的兼容格式Set-Cookie3的文件格式

      • add_cookie_header(requst) 向request对象中添加一个cookie对象

      • extract_cookies(response,request) 从http的response中提取cookie并储存在cookieJar对象中

      • make_cookies(response,request) 从http的response中提取cookie

      • set_cookie(cookie) 向cookieJar添加cookie对象

      • clear(keys) 清除名为key的cookie参数

      
      # 获取cookie
      
      from urllib.request import *
      from http.cookiejar import *
      
      url = 'http://www.baidu.com'
      headers = {
          'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36'
      }
      request = Request(url=url, headers=headers)
      
      response = urlopen(request)
      
      cookie = CookieJar()
      
      cookie.extract_cookies(response,request)
      
      print(cookie)
    • FileCookieJar 类,该类主要用于操作已经持久到文件中的cookie

      • 具有以上CookieJar的所有函数之外,额外添加了以下函数

      • filename 默认保存cookie的文件

      • save(filename = None,ignore_discard = False,ignore_expires = False ) 将cookie保存在文件中,方法未实现,但是在CookieJar的子类LWPCookieJar,MozillaCookieJar实现了其方法

      • load(filename = None,ignore_discard = False,ignore_expires = False ) 从文件中加载cookie

      • revert(filename = None,ignore_discard = False,ignore_expires = False ) 清除所有cookie,并从文件中重新加载cookie

    
    # 以LWPCookieJar为例,将cookie保存到文件中
    
    from urllib.request import *
    from http.cookiejar import LWPCookieJar
    
    url = 'http://www.baidu.com'
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36'
    }
    request = Request(url=url, headers=headers)
    
    response = urlopen(request)
    
    filecookie = LWPCookieJar()
    
    filecookie.extract_cookies(response,request)
    
    filecookie.save(r'a.txt')

cgi 通用网关接口支持模块、cgitb CGI脚本的回溯管理器模块

cgitb用于调试cgi脚本程序

  • enable() 将错误信息输出到访问的html页面

cgi是服务器运行时调用的外部程序,通过通用CGI接口与服务器通信,默认放在[‘/cgi-bin’, ‘/htbin’]目录下

  • 通常由两个部分组成

    • 第一部分为响应头,用于告知客户端传输数据的类型,后面跟空行,用于将响应体分开
    print("Content-Type: text/html")
    print()
    • 第二部分为响应的数据
  • 常用的头部信息

    • Content-type: 请求的资源类型对应的MIME信息
    • Content-Disposition: disposition-type;filename-parm 响应请求资源的下载方式
      • 其中disposition-type可以为attachment 弹出对话框下载,或者inline 直接显示在页面上
      • 其中filename-parm是filename = xx 规定下载时的文件名,用于规定下载时的文件名称
    • Expires: 响应过期的日期和时间
    • Location: 重定向到url的新的资源
    • Last-modified: 请求资源的最后修改日期
    • Content-length: 请求的内容长度
    • Set-Cookie: 设置cookie
  • 常用方法

    • parse_header(str) 将MIME标头解析为字典
    • parse_multipart(fp,pdict,encoding =“utf-8”,errors =“replace” ) 返回{字段名称:数据}的字典
    • print_form(form) 将接收的表格以html形式格式化
    • print_directory() 以html形式格式化当前目录
    • test() 将cgi作为主程序进行测试
  • FieldStorage(,key,filename,value)

    • 此类用于获取html中form输出的表单数据,仅需要实例化一次
    • FiledStorage()[key] 代表了表单中名为key的标签整体
    • FiledStorage()[key].value 代表了表单中key标签的值
    • getvalue(key) 当有多个值时,返回一个字符串列表
    • getlist(key) 返回名key标签下的所有字符串组成的列表
  • 编写一个最简单的CGI程序,如果需要访问该CGI程序,需要先启动一个CGI服务器,在前面已经学到过,在HTTPServer中导入CGIHTTPRequestHandler创建一个最简单的CGI服务器

import cgi
import cgitb

cgitb.enable()

print("Content-Type: text/html")
print()

html ='''

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>My First Python CGIh1>
body>
html>
'''
print(html)
  • CGI获取客户端使用GET方式发送的数据

    • 请求的url为http://127.0.0.1:8888/cgi-bin/cc.py?usr=jack&pwd=123456,可以看出,传递的数据以明文方式出现在url中

    • 传递的数据包含在请求头中

    • 在GET方式中,不应包含敏感数据,敏感数据应使用POST方式发送

# index.html中的内容

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>请输入文字h1>
    <form action="http://127.0.0.1:8888/cgi-bin/cc.py" method="GET" id="myform">
        <h2>账户:<input type="text" name="usr">h2>
        <h2>密码:<input type="text" name="pwd">h2>
        <button type="submit">发送button>
    form>
body>
html>

# CGI程序
import cgi
import cgitb

cgitb.enable()

print("Content-Type: text/html")
print()

form = cgi.FieldStorage()
usr = form.getvalue('usr')
pwd = form.getvalue('pwd')
html ='''

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>获取到的数据是:h1>
    <p>{0}p>
    <p>{1}p>
body>
html>
'''.format(usr,pwd)

print(html)
  • POST方式在上面的CGIHTTPRequestHandler中,不多进行赘述

    • POST方式发送数据,不会明文出现在url中,会存在于请求体的form-data中,所以相对于GET方式,要安全的多
  • 传递checkbox数据

# index.html内容是

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>请勾选h1>
    <form action="/cgi-bin/cc.py" method="POST" id="myform">
        <input type="checkbox" name="usr" value="on" > usr
        <input type="checkbox" name="pwd" value="on" > pwd
        <button type="submit">发送button>
    form>
body>
html>

# cgi程序
import cgi
import cgitb

cgitb.enable()

print("Content-Type: text/html")
print()

form = cgi.FieldStorage()
google = form.getvalue('google')
if google == on:
    r1 = 'google被选中'
else:
    r1 = 'google没有被选中'
baidu = form.getvalue('baidu')
if baidu == 'on':
    r2 = 'baidu被选中'
else:
    r2 = 'baidu没有被选中'
html ='''

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>获取到的数据是:h1>
    <p>{0}p>
    <p>{1}p>
body>
html>
'''.format(r1,r2)

print(html)
  • 传递radio数据
# index.html中的内容

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>请勾选h1>
    <form action="/cgi-bin/cc.py" method="POST" id="myform">
        <input type="radio" name="site" value="google" > 谷歌
        <input type="radio" name="site" value="baidu" > 百度
        <button type="submit">发送button>
    form>
body>

# cgi程序内容
import cgi
import cgitb

cgitb.enable()

print("Content-Type: text/html")
print()

form = cgi.FieldStorage()
value = form.getvalue('site')

html ='''

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>获取到的数据是:h1>
    <p>{0}p>
body>
html>
'''.format(value)

print(html)
  • 传递Textatrea数据
# index.html中的内容

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>请输入内容h1>
    <form action="/cgi-bin/cc.py" method="post">
        <Textarea name="text" cols="40" rows="4" >在这里输入内容....
        Textarea>
        <input type="submit">
    form>
body>
html>

# cgi程序中的内容
import cgi
import cgitb

cgitb.enable()

print("Content-Type: text/html")
print()

form = cgi.FieldStorage()
value = form.getvalue('text')

html ='''

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>获取到的数据是:h1>
    <p>{0}p>
body>
html>
'''.format(value)

print(html)
  • 传递下拉数据
# index.html中的内容

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>请输入内容h1>
    <form action="/cgi-bin/cc.py" method="post">
        <select name="sel" >
            <option value="baidu">百度option>
            <option value="google">谷歌option>
        select>
        <input type="submit">
    form>
body>
html>

# cgi程序中的内容
import cgi
import cgitb

cgitb.enable()

print("Content-Type: text/html")
print()

form = cgi.FieldStorage()
value = form.getvalue('sel')

html ='''

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>获取到的数据是:h1>
    <p>{0}p>
body>
html>
'''.format(value)

print(html)
  • 设置cookie
# 直接访问cgi程序,设置cookie,通过chrome即可查看设置的cookie
# cgi程序为:
import cgi,datetime
import cgitb
from http.cookies import *

cgitb.enable()

name = 'cgicookie'
now = datetime.datetime.utcnow()
time = (now + datetime.timedelta(days=10)).strftime('%a,%d-%m-%Y %H:%M:%S')
path = '/'
domain = '127.0.0.1'
cookie = SimpleCookie()
cookie['NAME'] = name
cookie['NAME']['expires'] = time
cookie['NAME']['path'] = path
cookie['NAME']['domain'] = domain

print("Content-Type: text/html")
print(cookie)
print()

html ='''

<html lang="en">
<head>
    
    Title
head>
<body>
    

cookie已经设置

body> html> ''' print(html)
  • 文件上传
# index.html中的内容

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>文件上传h1>
    <form action="/cgi-bin/cc.py" method="post" enctype="multipart/form-data">
        <p><input type="file" name="upload">p>
        <p><input type="submit">p>
    form>
body>
html>

# cgi程序为:
import cgi
import cgitb

cgitb.enable()

form = cgi.FieldStorage()
file = form['upload']
open(file.filename,'wb').write(file.value)

print("Content-Type: text/html")
print()

html ='''

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>已接收上传文件h1>
body>
html>
'''

print(html)
  • 文件下载
# 直接访问cgi程序,以下为cgi程序的内容
import cgi
import cgitb

cgitb.enable()

data = open(r'chromedriver.exe','rb').read()

print("Content-Disposition: attachment;filename=chromedriver.exe")
print()

print(data)

urlib URL处理模块

  • url 同一资源定位符

    • 格式: prot_sch://net_loc/path;params?query#frag

      • prot_sch 网络协议

      • net_loc 服务器所在地址 可进一步分割为多个组件

        • user 用户名
        • passwd 用户密码
        • host 服务器所在地址或服务器计算机名称(必须)
        • port 端口号(默认80)
      • path 文件或者CGI应用的路径

      • params 可选参数

      • query 连接符(&)分割的键值对

      • frag 文档中的特定锚点

  • request 请求url模块

    • Request(url,data = None,headers = {}) 类 构造一个复杂的请求对象,可以供urlopen函数使用

      • full_url 返回请求的url

      • host 返回请求的主机地址

      • method 返回请求的方法

      • add_header(key,value) 添加请求标头

      • has_header(key) 检查是否有key请求标头

      • remove_header(key) 删除名为key的请求标头

      • get_header(key) 返回名为key的标头值

      • header_items() 返回所有请求标头和值

    • urlopen(url,data) 打开一个url,发送data,返回HTTPResponse对象

    • 在HTTPResponse的基础上添加了以下方法

    • geturl() 返回请求资源的url

    • info() 返回页面的元信息

    • getcode() 返回响应的状态码

  • build_opener([handler,]) 返回一个OpenerDirector对象

  • install_opener(OpenerDirector对象) 将OpenerDirector对象设置为全局默认

  • OpenerDirector 类 该类主要用于通过添加相应的Handler构建一个自定义的urlopen对象,实现各种不同的访问需求

    • add_handler(Handler) 添加一个处理行为给OpenerDirector对象

    • open(url) 打开URL,返回HTTPResponse对象

    • error(proto,* args) 给定相应的参数处理错误

  • HTTPRedirectHandler 类,重定向处理程序

  • HTTPHandler 类,发送HTTP请求,可以为GET或POST

  • HTTPSHandler(debuglevel = 0,context = None,check_hostname = None ) 类,发送HTTPS请求,可以为GET或者POST

  • HTTPBasicAuthHandler(password_mgr = None ) 类,请求时需要账户密码登录

  • ProxyHandler(proxies = None ) 类,代理请求,需要在实例化的时候添加代理字典

  • ProxyBasicAuthHandler(password_mgr = None ) 类,需要用户名密码登录的代理

  • HTTPCookieProcessor(cookiejar) 类,Cookie处理

  • FileHandler 类,打开文件

  • FTPHandler 类,打开FTP文件

  • HTTPErrorProcessor 类,处理HTTP异常

    • http_response(req,reply) 对于错误,返回reply对象

    • https_response(req,reply) 对于错误,返回reply对象

  • 密码管理器对象,用于添加到各项需要认证的处理程序中

    • HTTPPasswordMgr 类,映射数据库,通过(realm, uri) -> (user, password)

      • add_password(realm, uri, user, passwd) 添加相应的账户,密码到管理器对象中,realm是指主机服务器的域信息一般为None,uri指服务器

      • find_user_password(realm, authuri) 返回指定服务器域中是否有定义的账户,如果有返回(账户,密码)元组,没有返回None

    • HTTPPasswordMgrWithDefaultRealm

      • 同上两个方法
    • HTTPPasswordMgrWithPriorAuth

    • 同上两个方法

    • update_authenticated(self, uri, is_authenticated=False)

    • is_authenticated(self, authuri)

使用默认函数访问url

from urllib.request import *

url = 'http://www.baidu.com'
response = urlopen(url)
print(response.read().decode())

使用Request对象构造请求

from urllib.request import *

url = 'http://www.baidu.com'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36',
'Host': 'www.baidu.com'
}
request = Request(url,headers=headers)
response = urlopen(request)
print(response.read().decode())

构造自定的访问器,获取cookie

from urllib.request import *
from http.cookiejar import *

url = 'http://www.baidu.com'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36',
'Host': 'www.baidu.com'
}
cookie = CookieJar()
openr = build_opener(HTTPCookieProcessor(cookie))
request = Request(url,headers=headers)
response = openr.open(request)
print(cookie)
print(response.read().decode())

# 或者

from urllib.request import *
from http.cookiejar import *

url = 'http://www.baidu.com'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36',
'Host': 'www.baidu.com'
}
cookie = CookieJar()
openr = OpenerDirector()
openr.add_handler(HTTPCookieProcessor(cookie))
openr.add_handler(HTTPHandler())
request = Request(url,headers=headers)
response = openr.open(request)
print(cookie)

构造自定访问器,使用用户名、密码登录

from urllib.request import *
from urllib.parse import *

login_url = r'https://www.douban.com/accounts/login'

data = urlencode({
'source': 'index_nav',
'form_email': 'XXXXX',
'form_password': 'XXXXX'
}).encode()

request = Request(url=login_url,data=data)
response = urlopen(request)
print(response.read().decode('utf-8','ignore'))

你可能感兴趣的:(Python 网络编程)