网络编程

网络编程

  • 网络:

  • 网络协议:一套规则

  • 网络模型:

    • 七层模型
      • 物理层
      • 数据链路层
      • 网络层
      • 传输层
      • 会话层
      • 表示层
      • 应用层
    • 四层模型
      • 链路层
      • 网络层
      • 传输层
      • 应用层
  • 每一层都有相应的协议负责交换信息或者协同工作

  • TCP/IP 协议簇

  • IP地址:负责在网络上唯一定位的一个机器

    • IP地址分五类ABCDE类
    • 是由四个数字段组成,每个数字段的取值是0-255
    • 192.168.xxx.xxx:局域网IP
    • 127.0.0.1:本机
    • IPV4,IPV6
  • 端口

    • 范围:0-65535
      • 知名端口:0-1023
      • 非知名端口:1024-

TCP/UDP协议

  • UDP: 非安全的不面向链接的传输

    • 安全性差
    • 大小限制64kb
    • 没有顺序
    • 速度快
  • TCP:基于链接的通信

  • SOCKET编程

    • socket(套接字): 是一个网络通信的端点,能实现不同主机的进程通信,网络大多基于socket完成
    • 通过IP+端口定位对方并发送消息的通信机制
    • 分为UDP和TCP
    • 客户端Client: 发起访问的一方
    • 服务器端Server: 接受访问的一方

UDP 编程

- Server端流程
    - 1. 建立socket,socket是负责具体通信得一个实例
    - 2. 绑定,为创建的socket指派固定的端口和ip地址
    - 3. 接受对方发送内容
    - 4. 给对方发送反馈,此步骤为非必须步骤
- Client端流程
    - 1. 建立通信的socket
    - 2. 发送内容到指定服务器
    - 3. 接受服务器给定的反馈内容
- 服务器案例v01
- 客户端案例v02
- 服务器要求永久运行,一般用死循环处理
- 改造的服务器版本案例V03
# 案例V01
'''
Server端流程
        - 1. 建立socket,socket是负责具体通信得一个实例
        - 2. 绑定,为创建的socket指派固定的端口和ip地址
        - 3. 接受对方发送内容
        - 4. 给对方发送反馈,此步骤为非必须步骤
'''
# socket模块负责socket编程
import socket

# 模拟服务器的函数
def serverFunc():
    # 1. 建立socket,socket是负责具体通信得一个实例
    
    #socket.AF_INET:使用IPV4协议簇
    #socket.SOCK_DGRAM: 使用UDP通信
    sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    
    # 2.绑定IP和port
    # 127.0.0.1: 这个ip地址代表的是机器本身
    # 7852:随手指定的端口号
    # 地址是一个tuple类型:(ip,port)
    addr = ("127.0.0.1",7852)
    sock.bind(addr)
    
    # 3.接收对方消息
    # 等待方式为死等,没有其他可能性
    # recvfrom接收的返回值是一个tuple,前一项表示数据,后一项表示地址
    # 参数的含义是缓冲区大小
    # rst = sock.recvfrom(500)
    data,addr = sock.recvfrom(500)
    
    print(data)
    print(addr)
    
    #4.发送过来的数据是bytes格式,必须通过解码才能得到str格式内容
    # decode默认参数是utf-8
    text = data.decode()
    print(type(text))
    print(text)
    
    # 给对方返回的消息
    rsp = "i love me"
    
    # 发送的数据需要编码成bytes格式
    data = rsp.encode()
    sock.sendto(data,addr)
    
if __name__ == "__main__":
    print("Starting server......")
    serverFunc()
    print("Ending server......")
# 案例v02
'''
Client端流程
        - 1. 建立通信的socket
        - 2. 发送内容到指定服务器
        - 3. 接受服务器给定的反馈内容
'''
import socket

def clientFunc():
    
    sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    
    text = "i love you"
    
    # 发送的数据必须是bytes格式
    data = text.encode()
    
    #发送
    sock.sendto(data, ("127.0.0.1",7852))
    
    data,addr = sock.recvfrom(200)
    
    data = data.decode()
    
    print(data)
    
if __name__ == "__main__":
    clientFunc()
# 案例v03
import socket
def serverFunc():
    # 1. 建立socket,socket是负责具体通信得一个实例
    
    #socket.AF_INET:使用IPV4协议簇
    #socket.SOCK_DGRAM: 使用UDP通信
    sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    
    # 2.绑定IP和port
    # 127.0.0.1: 这个ip地址代表的是机器本身
    # 7852:随手指定的端口号
    # 地址是一个tuple类型:(ip,port)
    addr = ("127.0.0.1",7852)
    sock.bind(addr)
    
    # 3.接收对方消息
    # 等待方式为死等,没有其他可能性
    # recvfrom接收的返回值是一个tuple,前一项表示数据,后一项表示地址
    # 参数的含义是缓冲区大小
    # rst = sock.recvfrom(500)
    data,addr = sock.recvfrom(500)
    
    print(data)
    print(addr)
    
    #4.发送过来的数据是bytes格式,必须通过解码才能得到str格式内容
    # decode默认参数是utf-8
    text = data.decode()
    print(type(text))
    print(text)
    
    # 给对方返回的消息
    rsp = "i love me"
    
    # 发送的数据需要编码成bytes格式
    data = rsp.encode()
    sock.sendto(data,addr)
    
if __name__ == "__main__":
    while True:
        serverFunc()

TCP编程

- 面向链接的传输,即每次传输之前需要先建立一个链接
- 客户端和服务器端两个程序需要编写
- Server端的编写流程
    - 1. 建立socket负责具体通信,这个socket其实只负责接受对方的请求
    - 2. 绑定端口和地址
    - 3. 监听接入的访问socket
    - 4. 接受访问的socket,可以理解接受访问即建立了一个通讯的链接通路
    - 5. 接受对方的发送内容,利用接收到的socket接收内容
    - 6. 如果有必要,给对方发送反馈信息
    - 7. 关闭链接通路
- Client端流程
    - 1. 建立通信socket
    - 2. 链接对方,请求跟对方建立通路
    - 3. 发送内容到对方服务器
    - 4. 接收对方的反馈
    - 5. 关闭链接通路
# server案例
import socket

# 模拟服务器的函数
def serverFunc():
    # 1. 建立socket,socket是负责具体通信得一个实例
    
    #socket.AF_INET:使用IPV4协议簇
    #socket.SOCK_STREAM: 使用TCP通信
    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    
    # 2.绑定IP和port
    # 127.0.0.1: 这个ip地址代表的是机器本身
    # 7852:随手指定的端口号
    # 地址是一个tuple类型:(ip,port)
    addr = ("127.0.0.1",7852)
    sock.bind(addr)
    
    #3.监听接入的反问socket
    sock.listen()
    
    while True:
        # 4.接收对方socket
        #accept返回的元组第一个元素值给skt,第二个值给addr
        skt,addr = sock.accept

        # 5.接受对方的内容
        # rst = sock.receive(500)
        msg = sock.recv(500)
        #发送过来的数据是bytes格式,必须通过解码才能得到str格式内容
        # decode默认参数是utf-8
        msg = msg.decode()
        rst = "Received msg:{0} from {1}".format(msg,addr)
        print(rst)

        # 6. 如果有必要,给对方发送反馈信息
        skt.send(rst.encode())

        #7.关闭链接通路
        skt.close()

    
if __name__ == "__main__":
    print("Starting server......")
    serverFunc()
    print("Ending server......")
# 客户端案例
import socket

def tcp_clt():
    #1. 建立通信socket
    socket = socket.socket(socket.AF_INET,sock.SOCK_STREAM)
    #2. 链接对方,请求跟对方建立通道
    addr = ("127.0.0.1",8998)
    sock.connect(addr)
    #3. 发送内容到对方服务器
    msg = "i love you"
    #4. 接受对方的反馈
    rst = sock.recv(500)
    print(rst.decode())
    # 5. 关闭链接通路
    sock.close()
    
if __name__ == "__main__":
    tcp_clt()

TCP和UDP的区别

    1. 安全性TCP>UDP
    1. UDP不面向链接,TCP基于链接
    1. 对系统资源的要求TCP>UDP
    1. UDP数据模式,TCP流模式
    1. TCP保证数据正确性,顺序性,UDP不保证,可能会丢失

FTP编程

  • FTP(File Transfer Protocal)
  • 用途:定制一些特殊的上传下载文件的服务
  • 用户分类:登录FTP服务器必须有一个账号
    • Real账户:注册账号
    • Guest账号:可能临时对某一类人的行为进行授权
    • Anonymous账户:匿名账户,允许任何人
  • FTP工作流程
    1. 客户端链接远程主机上的FTP服务器
    2. 客户端输入用户名和密码(或者“anonymous”和电子邮件地址)
    3. 客户端和服务器进行各种文件传输和信息查询操作
    4. 客户从远程FTPP服务器退出,结束传输
  • FTP文件表示
    • 分三段表示FTP服务器上的文件
      • HOST:主机地址,类似于ftp.mozilla.org,以ftp开头
      • DIR:目录,表示文件所在本地的路径
      • FILE:文件名称
      • 如果不想完整精确表示ftp上某一个文件,需要上述三部分组合在一起
import ftplib
import os
import socket

HOST = "ftp.acc.umu.se"
DIR ="Public/EFLIB"
FILE = 'README'

# 1.客户端链接远程主机上的FTP服务器
try:
    f = ftplib.FTP()
    f.set_debuglevel(2)
    f.connect(HOST)
except Exception as e:
    print(e)
    exit()
print("***Connect to host {0}".format(HOST))

# 2.客户端输入用户名和密码(或者“anonymous”和电子邮件地址)
try:
    f.login()
except Exception as e:
    print(e)
    exit()
print("***Logged in as 'anonymous'")    
    

# 3. 客户端和服务器进行各种文件传输和信息查询操作
try:
    f.cwd(DIR)
except Exception as e:
    print(e)
    exit()
print("***Changed dir to {0}".format(DIR))

try:
    f.retrbinary('RETR{0}'.format(FILE),open(FILE,"wb").write)
except Exception as e:
    print(e)
    exit()

# 4. 客户从远程FTPP服务器退出,结束传输
f.quit()

Mail编程

电子邮件的历史

  • 起源
    • 1969 Leonard k.教授发给同时的“LO”
    • 1971 美国国防部自主的阿帕网(Arpanet)的通讯机制
    • 通讯地址用@.
    • 1987年中国的第一份电子邮件“Across the Great Wall we can reach every corner in the world”
  • 管理程序
    • Euroda使邮件普及
    • Netscape,outlook,forxmail后来居上
    • Hotmail使用浏览器发送邮件

邮件工作流程

  • MUA(Mail User Agent)邮件用户代理

  • MTA(Mail Transfer Agent)邮件传输代理

  • MDA(Mail Delivery Agent)邮件投递代理

  • 流程

      1. MUA->MTA,邮件已经在服务器上了
      1. qq MTA->…>sina MTA,邮件在新浪的服务器上了
      1. sina MTA->sina MDA,此时邮件已经在你的邮箱里了
      1. sina MDA->MUA (Foxmail/OutLOOK),邮件下载到本地电脑
  • 编写程序

    • 发送:MUA->MTA with SMTP: Simple Mail transfer Protocal,包含MTA->MTA
    • 接受:MDA->MUA with POP3 and IMAP:Postoffice Protocal v3 and Internat Message Access Protocal v4(邮局协议版本3和网络信息通道协议)
  • 准备工作

    • 注册邮箱(以QQ邮箱为例)
    • 第三方邮箱需要特殊设置,以qq邮箱为例
      • 进入设置中心
      • 去得授权码
  • python for mail

    • SMTP协议负责发送邮件
      • 使用email模块构建邮件

        • 纯文本邮件
        • 案例01
      • HTML格式邮件发送

        • 准备HTML代码作为内容
        • 把邮件的subtype设为html
        • 发送
        • 案例02
      • 发送带附件的邮件

        • 可以把邮件看做是一个文本邮件和一个附件的合体
        • 一封邮件如果涉及多个部分,需要使用MIMEMutipart格式构建
        • 添加一个MIMEText正文
        • 添加一个MIMEBase或者MIMEText作为附件
        • 案例03
      • 添加邮件头,抄送等消息

        • mail[“from”]:表示发送者信息,包括姓名和邮件地址
        • mail[‘TO’]:表示接收者信息,包括姓名和邮件地址
        • mail[“Subject”]:表示摘要或者主题信息
        • 案例04
      • 同时支持html和text格式

        • 构建一个MIMEMultipart格式邮件
        • MIMEMultipart的subtype设置成alternative格式
        • 添加HTML和text邮件
        • 案例05
      • 使用smtplib模块发送邮件

# 案例01
import smtplib
from email.mime.text import MIMEText
# MIMEText三个主要参数
'''
1. 邮件内容
2. MIME子类型,在此案例用plain表示text案例
3. 邮件编码格式
'''
msg = MIMEText("Hello, i am xxx","plain","utf-8")

from_addr = "380638053@qq.com"

#授权码
from_pwd = "ewfierfeoinfowqfrweji"

to_addr = "1006185179@qq.com"

smtp_srv = "smtp.qq.com"

try:
    srv = smtplib.SMTP_SSL(smtp_srv.encode(),465)#SMTP协议默认端口25
    
    srv.login(from_addr,from_pwd)
    #发送邮件,三个参数
    '''
    1. 发送地址
    2. 接受地址,必须是list形式
    3. 发送内容,作为字符串发送
    '''
    srv.sendmail(from_addr,[to_addr],msg.as_string())
    srv.quit()
except Exception as e:
    print(e)
    

#案例02
# 案例01
import smtplib
from email.mime.text import MIMEText
# MIMEText三个主要参数
'''
1. 邮件内容
2. MIME子类型
3. 邮件编码格式
'''
contant_mail = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div{
            width: 100px;
            height: 100px;
            background: lightblue;
        }
        .mydiv{
            background: initial;
        }
    </style>
</head>
<body>
    <div class="mydiv">
        wowo
    </div>
</body>
</html>
"""
msg = MIMEText(contant_mail,"html","utf-8")

from_addr = "380638053@qq.com"

#授权码
from_pwd = "ewfierfeoinfowqfrweji"

to_addr = "1006185179@qq.com"

smtp_srv = "smtp.qq.com"

try:
    srv = smtplib.SMTP_SSL(smtp_srv.encode(),465)#SMTP协议默认端口25
    
    srv.login(from_addr,from_pwd)
    #发送邮件,三个参数
    '''
    1. 发送地址
    2. 接受地址,必须是list形式
    3. 发送内容,作为字符串发送
    '''
    srv.sendmail(from_addr,[to_addr],msg.as_string())
    srv.quit()
except Exception as e:
    print(e)
    

#案例03
from email.mime.text import MIMEText#构建附件使用
from email.mime.multipart import MIMEBase,MIMEMultipart#构建基础邮件使用

mail_mul = MIMEMultipart()
#构建邮件正文
mail_text = MIMEText("hello , ni hao","plain","utf-8")
#把构建好的邮件正文附加入邮件中
mail_mul.attach(mail_text)

with open("w02.html","rb") as f:
    s = f.read()
    #设置附件的MIME和文件名
    m = MIMEText(s,'base64','utf-8')
    m["Content-Type"] = "application/octet-stream"
    m["Content-Disposition"] = "attachment; filename='w02.html'"
    
    mail_mul.attach(m)

from_addr = "380638053@qq.com"

#授权码
from_pwd = "ewfierfeoinfowqfrweji"

to_addr = "1006185179@qq.com"

smtp_srv = "smtp.qq.com"

try:
    srv = smtplib.SMTP_SSL(smtp_srv.encode(),465)#SMTP协议默认端口25
    
    srv.login(from_addr,from_pwd)
    #发送邮件,三个参数
    '''
    1. 发送地址
    2. 接受地址,必须是list形式
    3. 发送内容,作为字符串发送
    '''
    srv.sendmail(from_addr,[to_addr],msg.as_string())
    srv.quit()
except Exception as e:
    print(e)
    
    
#案例04
from email.mime.text import MIMEText
from email.header import Header

msg = MIMEText("Hello ,i am coming","plain","utf-8")

head_from = Header("380638053@qq.com","utf-8")
msg["From"] = header_from

head_to = Header("1006185179@qq.com","utf-8")
msg["To"] = header_to

header_sub = Header("这是主题啊","utf-8")
msg["Subject"] = header_sub

from_addr = "380638053@qq.com"

#授权码
from_pwd = "ewfierfeoinfowqfrweji"

to_addr = "1006185179@qq.com"

smtp_srv = "smtp.qq.com"

try:
    srv = smtplib.SMTP_SSL(smtp_srv.encode(),465)#SMTP协议默认端口25
    
    srv.login(from_addr,from_pwd)
    #发送邮件,三个参数
    '''
    1. 发送地址
    2. 接受地址,必须是list形式
    3. 发送内容,作为字符串发送
    '''
    srv.sendmail(from_addr,[to_addr],msg.as_string())
    srv.quit()
except Exception as e:
    print(e)
    

# 案例05
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

msg =MIMEMultipart("alternative")

html_content = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div{
            width: 100px;
            height: 100px;
            background: lightblue;
        }
        .mydiv{
            background: initial;
        }
    </style>
</head>
<body>
    <div class="mydiv">
        wowo
    </div>
</body>
</html>
"""
msg_html = MIMEText(html_content,"html","utf-8")
msg.attach(msg_html)

msg_text = MIMEText("hello , ni hao","plain","utf-8")
#把构建好的邮件正文附加入邮件中
msg_mul.attach(msg_text)

from_addr = "380638053@qq.com"

#授权码
from_pwd = "ewfierfeoinfowqfrweji"

to_addr = "1006185179@qq.com"

smtp_srv = "smtp.qq.com"

try:
    srv = smtplib.SMTP_SSL(smtp_srv.encode(),465)#SMTP协议默认端口25,SSL为465端口
    
    srv.login(from_addr,from_pwd)
    #发送邮件,三个参数
    '''
    1. 发送地址
    2. 接受地址,必须是list形式
    3. 发送内容,作为字符串发送
    '''
    srv.sendmail(from_addr,[to_addr],msg.as_string())
    srv.quit()
except Exception as e:
    print(e)
    

POP3协议接受邮件

  • 本质上是MDA到MUA的一个过程
  • 从MDA下载下来的是一个完整的邮件结构体,需要解析才能得到每个具体的内容
  • 步骤:
    • 用poplib下载邮件结构体原始内容
        1. 准备相应的内容(邮件地址,密码,POP3实例)
        1. 身份认证
        1. 一般会先得到邮箱内邮件的整体列表
        1. 根据相应序号,得到某一封信的数据流
        1. 利用解析函数进行解析出相应的邮件结构体
    • 用email解析邮件的具体内容
# poplib负责从MDA到MUA下载
import poplib

# 以下包负责相关邮件结构解析
from email.parse import Parser
from email.header import decode_header
from email.utils import parseaddr

#得到邮件的原始内容
def getMsg():
    email = "1006185179@qq.com"
    pwd = "fewfwbgefnownowen"
    pop3_srv = "pop.qq.com"
    
    srv = poplib.POP3_SSL(pop3_srv)
    
    srv.user(email)
    srv.pass_(pwd)
    
    #stat返回邮件数量和占用空间
    msgs,counts = srv.stat()
    print("Messages:{0},size:{1}".format(msgs,counts))
    
    #list 返回所有邮件编号列表
    #mails 是所有邮件编号列表
    rsp,mails,octets = srv.list()
    print(mails)
    
    #获取最新一封邮件,注意,邮件索引号是从1 开始,最新代表索引最高
    index = len(mails)
    #retr 负责返回一个具体索引号的一封信的内容,此内容不具有可读性
    #lines 存储邮件最原始文本的每一行
    rsp,lines,octets = srv.retr(index)
    
    #获取整个邮件的原始文本
    msg_count = b'\r\n'.join(lines).decode("utf-8")
    
    #解析出整个结构体
    #参数是解码后的邮件整体
    msg = Parser().parsestr(msg_count)
    
    #关闭链接
    srv.quit()
    
    return msg

# 详细解析得到的邮件内容
# msg代表是邮件的原始内容
# ident代表的是邮件嵌套的层级
def parseMsg(msg, indent=0):
    if indent == 0:
        for header in ['From',"To",'Subject']:
            value = msg.get(header,'')
            if value:
                if header == "Subject":
                    value = decodeStr(value)
                else:
                    hdr,addr = parseaddr(value)
                    name = decodeStr(hdr)
                    value = "{0}{1}".format(name,addr)
            print("{0},{1}:{2}".format(indent,header,value))
            
    if (msg.is_multipart()):
        pasts = msg.get__playload()
        for n,part in enumerate(parts):
            print("{0}spart:{1}".format(''*indent,n))
            parseMsg(part,indent+1)
    else:
        content_type = msg.get_content_type()
        if content_type == "text/plain" or content_type == 'text/html':
            content = msg.get_playload(decode=True)
            charset = guessCharset(msg)
            if charset:
                content = content.decode(charset)
            print("{0}Text:{1}".format(indent,content))
        else:
            print("{0}Attachment:{1}".format(indent,content_type))
            
def decoderStr(s):
    value,charset = value.decode_header(s)[0]
    if charset:
        value = value.decode(charset)
    return value

def guessCharset(msg):
    charset = masg.get_charset()
    
    if charset is None:
        content_type = msg.get("Content-Type","").lower()
        pos = content_type.find("charset=")
        if pos >=0:
            charset = content_type[pos+8:].strip()
    return charset
if __name__ == "__main__":
    msg = getMsg()
    print(msg)
    parseMsg(msg,0)
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值