Python3网络编程与电子邮件(v3.7)

[TOC]

TCP/IP

IP协议负责把数据从一台计算机通过网络发送到另一台计算机。数据被分割成一小块一小块,然后通过IP包发送出去。由于互联网链路复杂,两台计算机之间经常有多条线路,因此,路由器就负责决定如何把一个IP包转发出去。IP包的特点是按块发送,途径多个路由,但不保证能到达,也不保证顺序到达。

IPv4实际上是一个32位整数,通常采用点分十进制表示法表示。如:192.168.0.1
IPv6实际上是一个128位整数,它是目前使用的IPv4的升级版,以字符串表示。如:2001:0db8:85a3:0042:1000:8a2e:0370:7334

TCP协议则是建立在IP协议之上的。TCP协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。TCP协议会通过握手建立连接,然后,对每个IP包编号,确保对方按顺序收到,如果包丢掉了,就自动重发。
许多常用的更高级的协议都是建立在TCP协议基础上的,比如用于浏览器的HTTP协议、发送邮件的SMTP协议等。

TCP编程

Socket是网络编程的一个抽象概念。通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/env python3
# -*-coding: utf-8 -*-

"""
服务端代码
AF_INET 指定使用IPv4协议
AF_INET6 指定使用IPv6协议
SOCK_STREAM 指定使用TCP协议
SOCK_DGRAM 指定使用UDP协议
"""

# 导入socket模块
import socket, threading

# 创建socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 监听接口
s.bind(('127.0.0.1', 9999))
# 等待最大连接数
s.listen(5)
print('Waiting for connection...')

# 定义线程处理方法
def tcplink(*args):
print('Accept new connection from %s:%s...' % addr)
sock.send(b'Welcome!')
while True:
# 接收消息
data = sock.recv(1024)
# 遇到exit时退出连接
if not data or data.decode('utf-8') == 'exit':
break
# 发送接收加工后的消息
sock.send('Hello %s'.encode('utf-8') % data)
print(data.decode('utf-8'))
# 关闭当前连接
sock.close()
print('Connection from %s:%s closed.' % addr)

while True:
# 接收一个新连接
sock, addr = s.accept()
print('--->',sock,addr)
# 创建新线程来处理TCP连接
t = threading.Thread(target=tcplink, args=(sock, addr))
t.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python3
# -*-coding: utf-8 -*-

"""客户端代码"""

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务端
s.connect(('127.0.0.1', 9999))
# 接收欢迎消息
print(s.recv(1024).decode('utf-8'))

while True:
# 输入发送的消息
msg = input("请输入内容:")
# 发送消息
s.send(msg.encode('utf-8'))
# 接收消息
data = s.recv(1024)
print('回复:',data.decode('utf-8'))
# 输入exit退出连接会话
if msg == 'exit':
break;
# 关闭连接
s.close()
print('已退出会话')

TCP是建立可靠连接,并且通信双方都可以以流的形式发送数据。相对TCP,UDP则是面向无连接的协议。使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包。但是,UDP传输数据不可靠,但它的优点是和TCP比,速度快。

电子邮件

Pythoy提供mail(构造邮件)和smtplib(发送邮件)两个模块对SMTP支持。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/usr/bin/env python3
# -*-coding: utf-8 -*-

import os
import logging
import smtplib
from email.header import Header
from email.utils import formataddr
from email.mime.text import MIMEText

logging.basicConfig(level=logging.DEBUG)


class MailSMTP(object):
__site_name = os.environ['SITE_NAME']
__smtp_user = os.environ['SMTP_USER']
__smtp_pass = os.environ['SMTP_PASS']
__smtp_host = os.environ['SMTP_HOST']
__smtp_port = os.environ['SMTP_PORT']
__sender_name = os.environ['SENDER_NAME']

def __init__(self, to_addr):
self.__to_addr = to_addr

# 发送邮件
def send_mail(self, msg):
logging.debug(msg)
# 封装消息
message = MIMEText(msg, 'html', 'utf-8')
message['From'] = formataddr(['%s' % self.__site_name, '%s' % self.__smtp_user])
message['To'] = formataddr(['我', '%s' % self.__to_addr[0]])
message['Subject'] = Header('来自%s...' % self.__sender_name, 'utf-8')

# 设置服务参数
server = smtplib.SMTP(self.__smtp_host, self.__smtp_port)
server.set_debuglevel(1)
server.login(self.__smtp_user, self.__smtp_pass)
server.sendmail(self.__smtp_user, self.__to_addr, message.as_string())
server.quit()

>>> to_addr = [],msg = ''
>>> mail_smtp = MailSMTP(to_addr)
>>> mail_smtp.send_mail(msg)