计网自顶向下(Web服务器+UDPping+邮件客户端)

目录

🐖前言

🌼Web服务器(作业1)

🌳过程

🌳解释

🔥代码

🌼UDPping程序(作业2)

🌳过程

🌳解释

Client

Server

整体逻辑

🔥代码

🌼邮件客户端(作业3)

🍍前置

🌳过程

🌳解释

(3) 邮件结束符

(4)base64库,b64encode(), encode(), decode()

(6) 接收信息

(8) SMTP命令

(9)encode() 和 decode()

🔥代码


🐖前言

19个Wireshark + 课后实验 + TCP/UDP,不包括很多可选练习,比如作业1(Web服务器),包含2个可选练习

(1)实现多线程服务器

(2)手写HTTP客户端代替浏览器来测试服务端请求

这部分等以后有时间了再看,先提高效率学完计网,搞定WebServer先,ddl更重要

以下是作业1,2,3,4的实验,属于应用层

源码地址👇

moranzcw/Computer-Networking-A-Top-Down-Approach-NOTES: 《计算机网络-自顶向下方法(原书第6版)》编程作业,Wireshark实验文档的翻译和解答。 (github.com)

🌼Web服务器(作业1)

🌳过程

Github代码用git bash,git clone到本地,导入vscode

打开cmd,ipconfig,找到INET1里,IPv4后的地址,我的是192.168.***.***

打开新的cmd,对应目录,运行Webserver代码

打开另一个新的cmd来模拟另一台主机,cmd里打开浏览器(注意,此时html代码和WebServer.py代码处于同一目录下)

然后浏览器出现

如果输入不存在的网页html

6789端口号是随便指定的,只要在端口范围内,并且没被占用即可

如何查看是否被占用

(1)Windows,打开Powershell,输入

Test-NetConnection -ComputerName localhost -Port 6789

TcpTestSucceeded : False,表示未被占用,可以使用

(2)cmd输入

netstat -ano

查看所有使用中的端口号

🌳解释

以下是关于代码的详细解释

from socket import *
serverSocket = socket(AF_INET, SOCK_STREAM)

导入了socket模块并创建了一个TCP套接字,使用的协议族是IPv4(AF_INET),传输方式是流(SOCK_STREAM)

serverSocket.bind(('', 6799)) 

 将TCP欢迎套接字绑定到指定的端口号6799和任何可用的IP地址。为空字符串意味着服务器将在本机所有可用的网络接口上监听进来的连接请求

connectionSocket, addr = serverSocket.accept()

(1) connectionSocket是一个代表与客户端建立的TCP连接的套接字,它用于在服务器和客户端之间进行通信

(2)addr是一个元组,包含了客户端的IP地址和端口号。可以使用addr[0]访问IP地址,使用addr[1]访问端口号。这个元组表示与连接套接字关联的客户端的网络地址

message = connectionSocket.recv(1024) 

 从连接套接字中接收报文,其长度不超过1024字节

filename = message.split()[1]

将请求报文拆分并提取出请求的文件名,具体👇 

 message.split()是将message字符串按空格拆分成一个字符串列表

message = "GET /hello.html HTTP/1.1\r\nHost: www.example.com\r\n\r\n"
message_list = message.split()
print(message_list)

输出

['GET', '/hello.html', 'HTTP/1.1', 'Host:', 'www.example.com']

filename = message.split()[1]提取了拆分后的第二个元素(即'/hello.html'),它是客户端请求的文件名。

[1]表示获取列表中的第二个元素(索引从0开始)。因此filename = message.split()[1]语句的作用是从拆分后的列表中提取请求的文件名

f = open(filename[1:])
outputdata = f.read()

 打开请求的文件并读取其内容。注意,这里filename[1:]是为了去掉请求报文中的"/"。

header = ' HTTP/1.1 200 OK\nConnection: close\nContent-Type: text/html\nContent-Length: %d\n\n' % (len(outputdata))
connectionSocket.send(header.encode())

设置HTTP响应头和内容,其中包括状态代码,内容类型,内容长度等信息。在此之后,它通过套接字将响应头发送给客户端。具体👇 

  • HTTP/1.1:这是HTTP协议的版本号,表示使用的是HTTP 1.1版本。
  • 200:这是状态代码,表示请求成功。这里使用的是200,表示服务器成功处理了客户端的请求并返回相应的内容。
  • OK:这是状态消息,与状态代码相对应,表示请求成功。
  • Connection: close:这是指定连接选项的字段,告诉客户端在响应之后关闭连接。这里使用close选项,表示服务器在发送完响应后关闭与客户端的连接。
  • Content-Type: text/html:这是指定响应内容类型的字段,告诉客户端接收到的是HTML类型的内容。在这里,服务器假设响应的内容为HTML文档。
  • Content-Length: %d:这是指定响应内容长度的字段,告诉客户端响应的实体主体内容的长度。%d是一个占位符,后面的(len(outputdata))将会填充实际的内容长度。
  • \n\n:这是两个换行符,表示头部信息结束,后面是实体主体内容
for i in range(0, len(outputdata)):connectionSocket.send(outputdata[i].encode())

 将请求的文件内容发送到套接字,具体👇

此处的 outputdata 对应字符串 HelloWorld.html

encode()是将这个字符转换为字节流的方法。encode()方法将Unicode字符串编码为字节序列,以便可以在网络上进行传输。

connectionSocket.close()

 关闭套接字来结束与客户端的通信

except IOError:header = ' HTTP/1.1 404 Not Found'connectionSocket.send(header.encode())connectionSocket.close()

🔥代码

#import socket module
from socket import *
serverSocket = socket(AF_INET, SOCK_STREAM)
# Prepare a server socket
# bind()的参数只有一个, 是ip和端口结合的套接字
serverSocket.bind(('', 6799)) # 将TCP欢迎套接字绑定到指定端口
serverSocket.listen(1) # 最大连接数1while True:# Establish the connectionprint('Ready to serve')connectionSocket, addr = serverSocket.accept() # 接受客户端请求后,建立新的TCP连接套接字try:message = connectionSocket.recv(1024) # 获取客户发送的报文filename = message.split()[1]f = open(filename[1:])outputdata = f.read();# Send the content of the requested file to the clientheader = ' HTTP/1.1 200 OK\nConnection: close\nContent-Type: text/html\nContent-Length: %d\n\n' % (len(outputdata))connectionSocket.send(header.encode())for i in range(0, len(outputdata)):connectionSocket.send(outputdata[i].encode())connectionSocket.close()except IOError:# Send response message for file not foundheader = ' HTTP/1.1 404 Not Found'connectionSocket.send(header.encode())# Close client socketconnectionSocket.close()
serverSocket.close()

🌼UDPping程序(作业2)

🌳过程

两个cmd模拟两台主机

server👇

另一台主机👇

🌳解释

Client

  1. from socket import *:导入socket模块,这个模块提供了网络通信所需的函数和类。
  2. import time:导入time模块,用于获取当前时间。
  3. serverName = '192.168.15.1':定义服务器地址,这里使用一个远程主机的IP地址。
  4. serverPort = 12000:定义服务器指定的端口号。
  5. clientSocket = socket(AF_INET, SOCK_DGRAM):创建UDP套接字,使用IPv4协议。
    • AF_INET表示使用IPv4地址族。
    • SOCK_DGRAM表示使用UDP协议。
  6. clientSocket.settimeout(1):设置套接字超时时间为1秒。
  7. for i in range(0, 10)::循环10次,发送10个ping消息。
  8. sendTime = time.time():获取当前时间作为发送时间。
  9. message = ('Ping %d %s' % (i+1, sendTime)).encode():生成包含序列号和发送时间的消息,并将其编码为字节串以便发送👇

'Ping %d %s' % (i+1, sendTime)表示将i+1和sendTime插入到字符串'Ping %d %s'中的%d和%s处,%d表示整数类型,%s表示字符类型(包括字符串)。

例如,当i=0和sendTime=1635558427.123456时,上述代码的结果是'Ping 1 1635558427.123456'

  1. try::尝试执行以下代码块。
  2. clientSocket.sendto(message, (serverName, serverPort)):将消息发送到服务器。
    • sendto()函数用于向特定地址发送UDP数据报。
  3. modifiedMessage, serverAddress = clientSocket.recvfrom(1024):接收服务器的响应消息,并同时获取服务器地址。
    • recvfrom()函数用于接收UDP数据报,返回接收到的数据和发送方的地址👇

(1)recvfrom()函数用于接收UDP数据报,并返回两个值:接收到的数据和发送方的地址。发送方的地址由IP地址和端口号的组合表示

(2)IP地址用于标识网络中的主机,而端口号则用于标识主机上运行的应用程序或服务

  1. rtt = time.time() - sendTime:计算往返时间(RTT)👇

rtt = round trip time  往返时间

  1. print('Sequence %d: Reply from %s RTT = %.3fs' % (i+1, serverName, rtt)):显示收到响应的信息,包括序列号、服务器地址和RTT👇

(1)"%.3fs" 是一个格式化字符串,用于将浮点数值插入到字符串中,并指定小数点后保留三位小数

(2)例如,一个浮点数值rtt为2.34567,则"%.3fs" % rtt 的结果将是"2.346s",保留了三位小数并转换为字符串类型

  1. except Exception as e::如果出现异常,则执行以下代码块。
  2. print('Sequence %d: Request timed out' % (i+1)):显示请求超时的信息。
  3. clientSocket.close():关闭套接字。

Server

  1. from socket import *:导入socket模块。
  2. import random:导入random模块,用于生成随机数。
  3. serverSocket = socket(AF_INET, SOCK_DGRAM):创建UDP套接字。
  4. serverSocket.bind(('', 12000)):将IP地址和端口号绑定到套接字上。
    • ''表示使用任意可用的IP地址。
  5. while True::无限循环,不断处理客户端的请求。
  6. rand = random.randint(0, 10):生成一个0到10之间的随机数。
  7. message, address = serverSocket.recvfrom(1024):接收客户端的请求消息,同时获取客户端的地址。
  8. message = message.upper():将接收到的消息转换为大写形式。
  9. if rand < 4::如果随机数小于4,模拟丢包,不回复客户端。
  10. continue:继续下一次循环。
  11. serverSocket.sendto(message, address):向客户端发送响应消息。
    • sendto()函数用于向特定地址发送UDP数据报

整体逻辑

  1. 客户端通过UDP套接字向服务器发送ping消息。
  2. 服务器接收到客户端的消息后,根据随机数决定是否丢弃该消息。
  3. 如果服务器不丢弃消息,则将消息转换为大写形式并回复客户端。
  4. 客户端收到服务器的响应后,计算往返时间(RTT)并显示结果。
  5. 如果在超时时间内未收到服务器的响应,则显示请求超时的消息。
  6. 循环10次,完成10个ping请求。
  7. 最后关闭客户端的套接字

🔥代码

Client

from socket import *
import timeserverName = '192.168.15.1' # 服务器地址,本例中使用一台远程主机
serverPort = 12000 # 服务器指定的端口
clientSocket = socket(AF_INET, SOCK_DGRAM) # 创建UDP套接字,使用IPv4协议
clientSocket.settimeout(1) # 设置套接字超时1秒for i in range(0, 10):sendTime = time.time()message = ('Ping %d %s' % (i+1, sendTime)).encode() # 生成数据报,编码为tytes以便发送try:clientSocket.sendto(message, (serverName, serverPort)) # 将信息发送到服务器modifiedMessage, serverAddress = clientSocket.recvfrom(1024) # 从服务器接受信息,同时得到服务器地址rtt = time.time() - sendTime # 计算往返时间print('Sequence %d: Reply from %s    RTT = %.3fs' % (i+1, serverName, rtt)) # 显示信息except Exception as e:print('Sequence %d: Request timed out' % (i+1))clientSocket.close() # 关闭套接字

Server

from socket import *
import random# create a UDP socket
# notice the use of SOCK_DGRAM for UDP packets
serverSocket = socket(AF_INET, SOCK_DGRAM)
# Assign(分配) IP address and port number to socket
serverSocket.bind(('', 12000))while True:# Generate random number(生成随机数) in the range of 0 to 10rand = random.randint(0, 10)# Receive the client packet along with the address it is coming frommessage, address = serverSocket.recvfrom(1024)# Capitalize(使大写) the message from the clientmessage = message.upper()# If rand is less is than 4, we consider the packet lost and do not respondif rand < 4:continue# Otherwise, the server respondsserverSocket.sendto(message, address)

🌼邮件客户端(作业3)

🍍前置

关于SMTP👇

介绍

当我们发送一封电子邮件时,SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)起着至关重要的作用。SMTP 是用于在网络上传输电子邮件的标准协议,它定义了电子邮件是如何被发送和接收的

重点

  1. 寄信流程: 当你发送一封电子邮件时,你的邮件客户端(如Gmail、Outlook等)会将这封邮件发送给你所使用的邮件服务器。这个过程就是通过 SMTP 完成的

  2. 转发邮件: SMTP 也用于将邮件从一个邮件服务器传输到另一个邮件服务器。例如,当你发送一封邮件给另一个域名的邮箱时,你的邮件服务器就会使用 SMTP 将邮件传输到对方的邮件服务器

  3. 端口: SMTP 默认使用端口25进行通信,但为了安全起见,常常也会使用加密端口如587或465。这些端口提供了加密和身份验证功能,以保护邮件传输过程中的数据安全

  4. 简单性: SMTP 的"Simple"部分意味着它的设计相对简单,易于理解和实现。这使得它成为电子邮件传输的基本协议    

关于MX记录👇

(1)邮件交换记录(Mail Exchange record)的缩写

在域名系统(DNS)中,MX记录指定了负责接收该域名电子邮件的邮件服务器。当某人发送电子邮件到一个特定的域名时,发件人的邮件服务器会查询目标域名的MX记录,以确定应该将邮件传递到哪个邮件服务器 

(2)包括两个部分:优先级邮件服务器地址

优先级指定了邮件服务器的优先顺序,当一个域名有多个MX记录时,优先级较高的邮件服务器会被优先选择。邮件服务器地址则是指定了接收该域名邮件的邮件服务器的地址

(3)举例

一个域名可能具有多个MX记录,每条记录对应一个邮件服务器,而这些邮件服务器可能是按照优先级排序的,这样就可以确保即使主要的邮件服务器不可用,电子邮件仍然可以被正确地发送到备用的邮件服务器上

补充理解👇

如何验证 Email 地址:SMTP 协议入门教程 - 阮一峰的网络日志 (ruanyifeng.com)

SMTP协议详解及工作过程_51CTO博客_smtp协议

🌳过程

(1)首先你需要一个163和一个qq邮箱

(2)登录163邮箱,可以先看看这个👇

(3)开启SMTP (Simple Mail Transfer Protocol)

具体操作👇

首页这里有个设置,点击

然后手机扫码发送短信授权

把这串字符作为代码中的密码即可 

(4)将代码中的发送 / 接受邮箱,用户名和授权码改为自己的

第一次出现以下BUG👇

正确应该是 235 Authentication successfully

而不是535 Error: authentication failed

然后一看,发现改错代码了👇

对应修改后,成功!👇

163邮箱👇(发)

qq邮箱👇(收)

🌳解释

(1)整体思路

  1. 导入模块:从Python标准库中导入了socketbase64模块,用于网络通信和Base64编码。

  2. 设置邮件内容相关信息:包括邮件主题、类型和内容,以及邮件结束符号。

  3. 选择邮件服务器:设置邮件服务器的地址为"smtp.163.com"。

  4. 设置发件人和收件人的邮箱地址。

  5. 对发件人的认证信息进行Base64编码,包括用户名和密码。

  6. 创建一个套接字(socket)clientSocket,并与邮件服务器建立TCP连接​​​​​​

  7. 通过套接字与邮件服务器进行交互:

    • 发送HELO命令并打印服务器响应。
    • 进行身份验证,包括发送用户名和密码,并接收服务器的响应进行验证。
  8. 发送邮件相关命令:

    • 发送MAIL FROMRCPT TO命令,用于指定发件人和收件人。
    • 发送DATA命令表示即将发送邮件内容。
    • 发送邮件内容,并以单个点作为结束标识。
    • 发送QUIT命令表示退出连接。
  9. 关闭套接字,断开连接

(2) 邮箱服务器SMTP地址

(3) 邮件结束符

endmsg = "\r\n.\r\n"  # 邮件结束符

在SMTP协议中,当发送完整的邮件内容后,需要使用"\r\n.\r\n"来表示邮件内容的结束。这个字符串告诉邮件服务器已经发送完所有邮件数据,服务器可以开始处理这封邮件了

"回车"(\r)指示打印头或光标返回到当前行的开头

"换行"(\n)指示将光标移动到下一行,并且可以包括回车操作以定位到下一行的开头

  • 在 Unix、Linux、macOS 等系统中,使用的是换行符(\n),即表示为一个字符。
  • 在 Windows 系统中,通常使用回车加换行的组合(\r\n)表示换行

实际的文本文件中,换行通常表示为回车加换行的组合(\r\n),这样可以确保在不同操作系统上都能正确地显示换行效果 

所以,"\r\n.\r\n" 用于结束邮件的发送,它包含两个换行和一个句点,用于标记邮件的结束 

(4)base64库,b64encode(), encode(), decode()

# Auth information (Encode with base64) (认证信息,使用base64编码)
username = base64.b64encode(fromaddress.encode()).decode()
password = base64.b64encode("*************".encode()).decode()

(一) 

fromaddress,邮箱地址的字符串,它包含用户名和域名

比如"user@example.com",其中"user"是邮箱的用户名,"example.com"是邮箱的域名

  • base64是一个Python标准库,提供了对Base64编码和解码的支持。
  • b64encodebase64库中的一个函数,用于对数据进行Base64编码

encode(): 这个方法用于将字符串编码为指定的编码格式,返回一个 bytes 对象

decode(): 这个方法用于将 bytes 对象解码为指定的字符串格式,返回一个字符串 

(二) 

a. encode()将字符串编码为字节对象

(因为字符串是由Unicode字符组成的,而计算机处理和传输数据时一般使用字节数据。因此,需要将字符串转换为字节对象以进行后续的处理和编码)

b.  b64encode()对字节对象进行base64编码

(Base64编码是将数据转换为只包含可打印ASCII字符的编码形式。它通常用于在文本协议中传输二进制数据)

c. decode()将编码后的结果解码为字符串

(将字节对象转换为Base64编码后,得到的是一个表示编码形式的字节序列。如果我们要将其作为字符串使用或展示,需要使用decode()方法将其解码为字符串形式)

(三) 

字符串通过字节编码、Base64编码和解码操作,获得的结果是一个与原来字符串内容相同的新字符串。但是它们的数据类型和编码形式是不同的 

(5)创建套接字,并与服务器建立TCP连接

# 创建套接字并与邮件服务器建立TCP连接
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((mailserver, 25)) # 邮箱地址和端口号

socket() 创建一个套接字对象 clientSocket

AF_INET 参数表示使用 IPv4 地址族,SOCK_STREAM 参数表示这是一个面向连接的 TCP 套接字

(mailserver, 25) 是一个元组,包含了要连接的目标服务器的地址和端口号

一旦调用了 connect 方法,客户端套接字就会尝试连接到指定的邮件服务器

(6) 接收信息

recv = clientSocket.recv(1024).decode()

使用 recv 方法从服务器端接收最多 1024 字节的数据,并将其解码为字符串

这个方法会阻塞程序,直到有数据到达或者连接关闭,如果没有数据到达,传输失败,print(recv)将不会输出任何结果 

换种解释就是👇

.recv 方法是在 Python 的 socket 编程中用于接收数据的方法。它用于从连接的另一端接收数据,其语法通常为 socket.recv(buffer_size)。其中,buffer_size 参数指定了一次性可以接收的最大数据量。调用 .recv 方法将会阻塞程序直到有数据到达,或者直到连接被关闭

(7) Python语法

if recv1[:3] != '250':print('250 reply not received from server.')

[:3] 表示前3个字符

(8) SMTP命令

"HELO" 等命令是 SMTP 协议规定的命令之一,用于客户端向服务器打招呼并标识自己。这个命令是固定的,不能随意更改

  1. MAIL FROM: sender@example.com\r\n 这是用于指定邮件的发件人地址的命令。在这个例子中,使用了字符串拼接来构造这个命令,并通过 clientSocket 发送到邮件服务器。

  2. RCPT TO: recipient@example.com\r\n 这是用于指定邮件的收件人地址的命令。类似地,这个命令也是用字符串拼接构造的,并发送到邮件服务器。

  3. DATA\r\n 这个命令告诉邮件服务器即将发送邮件数据。一旦收到这个命令,服务器会准备接收邮件内容。

  4. message = 'from:' + fromaddress + '\r\n' ... 这段代码构造了邮件的内容,包括发件人、收件人、主题、内容类型等信息,并将其转换成符合 SMTP 协议格式的字符串。

  5. clientSocket.sendall(message.encode()) 这里使用 sendall() 方法发送邮件内容的字符串到服务器。

  6. clientSocket.sendall(endmsg.encode()) endmsg 可能是表示邮件内容结束的标识,通过 sendall() 发送到服务器。

  7. recv = clientSocket.recv(1024).decode() 这里是接收服务器返回的响应消息,然后根据响应消息进行相应的处理,比如判断是否成功发送邮件

(9)encode() 和 decode()

发送数据👇 

send()方法是用来发送TCP数据的,而sendall()方法则会在必要时将所有数据发送完毕 

  • 每次调用send或者sendall发送数据之前都需要通过encode方法将字符串编码为字节对象,这是因为网络传输的数据必须是字节类型。
  • 调用encode方法后,会将字符串转换为特定的字节编码形式(如UTF-8),得到一个字节对象作为发送的数据

接受数据👇

  • 每次从套接字接收到数据后,获得的是字节对象,需要通过decode方法将字节对象解码成字符串,以便我们能够处理和理解这些数据。
  • 调用decode方法后,会根据指定的编码方式将字节对象解码为字符串

(10)前半部分多次 send(), sendall(), recv() 的作用

(一)客户端需要将邮件按照 SMTP 协议要求的格式逐步发送给服务器,以确保服务器能够正确地接收并处理邮件内容

(二)调用了 recv 方法来接收服务器的响应

客户端可以了解到是否有任何错误发生,以及服务器是否成功接收并处理了客户端发送的邮件内容

最后的几行message,作用是发送邮件信息,要求遵循SMTP协议规范 

(11)MAIL FROM 和 RCPT TO 命令

clientSocket.sendall(('MAIL FROM: <' + fromaddress + '>\r\n').encode())clientSocket.sendall(('RCPT TO: <' + toaddress + '>\r\n').encode())

 < 和    在这个代码中是为了表示电子邮件地址的开始和结束符号。在SMTP协议中,使用<>来标识一个完整的电子邮件地址。在这段代码中,   和    用于包围 fromaddress 和 toaddress 变量,在电子邮件中指定发送人和收信人

🔥代码

当我尝试去掉代码中的部分send, sendall(), recv时,程序报错502,因为邮件服务端对认证方式有限制,需要按特定格式发送(也就是说,只保留开头部分和结尾message部分,去掉中间的多次认证,是不行的,任何一个命令,都不能少)

# 导入模块
from socket import *
import base64# Mail content
subject = "宝贝"  # 标题
contenttype = "text/plain"  # 类型
msg = "想我了没"  # 内容
endmsg = "\r\n.\r\n"  # 邮件结束符# Choose a mail server (SMTP服务器地址)
mailserver = "smtp.163.com"# Sender and reciever (发件人和收件人)
fromaddress = "***********@163.com"
toaddress = "************@qq.com"# Auth information (Encode with base64) (认证信息,使用base64编码)
# base64编码, 以便进行SMTP身份认证
username = base64.b64encode(fromaddress.encode()).decode()
password = base64.b64encode("*************".encode()).decode()# Create socket called clientSocket and establish a TCP connection with mailserver
# 创建套接字并与邮件服务器建立TCP连接
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((mailserver, 25)) # 邮箱地址和端口号recv = clientSocket.recv(1024).decode()
print(recv)
if recv[:3] != '220':print('220 reply not received from server.')# Send HELO command and print server response.
# 发送HELO命令
heloCommand = 'HELO Alice\r\n'
clientSocket.send(heloCommand.encode()) # 发送命令
recv1 = clientSocket.recv(1024).decode() # 接收响应
print(recv1)
if recv1[:3] != '250':print('250 reply not received from server.')# Auth (认证)
# 身份验证的头部信息
# 发送'AUTH LOGIN\r\n'到服务器
clientSocket.sendall('AUTH LOGIN\r\n'.encode())# 从客户端socket接受消息,长度为1024字节,解码为字符串
recv = clientSocket.recv(1024).decode()
print(recv)
# 检查前3个字符
if (recv[:3] != '334'):print('334 reply not received from server')# 用户名添加到消息末尾并发送给服务器
clientSocket.sendall((username + '\r\n').encode())# 从客户端socket接收消息
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '334'):print('334 reply not received from server')# 密码添加到消息末尾并发送给服务器
clientSocket.sendall((password + '\r\n').encode())# 从客户端socket接收消息, 并解码为字符串
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '235'):print('235 reply not received from server')# Send MAIL FROM command and print server response.
# 发送MAIL FROM命令
clientSocket.sendall(('MAIL FROM: <' + fromaddress + '>\r\n').encode())
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '250'):print('250 reply not received from server')# Send RCPT TO command and print server response.
# 发送RCPT TO命令
clientSocket.sendall(('RCPT TO: <' + toaddress + '>\r\n').encode())
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '250'):print('250 reply not received from server')# Send DATA command
# 发送DATA命令
clientSocket.send('DATA\r\n'.encode())
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '354'):print('354 reply not received from server')# Send message data
# 发送邮件内容
message = 'from:' + fromaddress + '\r\n'
message += 'to:' + toaddress + '\r\n'
message += 'subject:' + subject + '\r\n'
message += 'Content-Type:' + contenttype + '\r\n'
message += '\r\n' + msg
clientSocket.sendall(message.encode())# Message ends with a single period (邮件以单个点结束)
clientSocket.sendall(endmsg.encode())
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '250'):print('250 reply not received from server')# Send QUIT command and get server response
# 发送QUIT命令
clientSocket.sendall('QUIT\r\n'.encode())# 关闭套接字 close connection
clientSocket.close()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/140771.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ChineseChess.2023.11.13.01

中国象棋残局模拟器ChineseChess.2023.11.13.01

正交矩阵的定义

对于n阶矩阵A&#xff0c;如果&#xff0c;其中为单位矩阵&#xff0c;为A的转置矩阵&#xff0c;那么就称A为正交矩阵。 对于正交矩阵&#xff0c; 对于正交矩阵&#xff0c;其列向量都是单位向量&#xff0c;行向量都是单位向量

【matlab】KMeans KMeans++实现手写数字聚类

目录 matlab代码kmeans matlab代码kmeans MNIST DATABASE下载网址: http://yann.lecun.com/exdb/mnist/ 聚类 将物理或抽象对象的集合分成由类似特征组成的多个类的过程称为聚类(clustering)。 对于给定N个n维向量x1&#xff0c;…&#xff0c;xN∈Rn&#xff0c;聚类的目标…

亚马逊云科技Zero ETL集成全面可用,可运行近乎实时的分析和机器学习

亚马逊云科技数据库、数据分析和机器学习全球副总裁Swami Sivasubramanian曾指出&#xff1a;“数据是应用、流程和商业决策的核心。”如今&#xff0c;客户常用的数据传输模式是建立从Amazon Aurora到Amazon Redshift的数据管道。这些解决方案能够帮助客户获得新的见解&#x…

通讯协议学习之路(实践部分):SPI开发实践

通讯协议之路主要分为两部分&#xff0c;第一部分从理论上面讲解各类协议的通讯原理以及通讯格式&#xff0c;第二部分从具体运用上讲解各类通讯协议的具体应用方法。 后续文章会同时发表在个人博客(jason1016.club)、CSDN&#xff1b;视频会发布在bilibili(UID:399951374) 本文…

Spring的Redis客户端

如何在Spring中操作redis 在创建springboot项目的时候引入redis的依赖. 在配置文件里指定redis主机的地址和端口,此处我们配置了ssh隧道,所以连接的就是本机的8888端口. 创建一个controller类,注入操作redis的对象. 前面使用jedis,是通过jedis对象里的各种方法来操作redis的,此…

Ionic组件 ion-list ion-list-header

1 ion-list 列表由多行项目组成&#xff0c;这些项目可以包含 text, buttons, toggles, icons, thumbnails等。列表通常包含具有类似数据内容的项目&#xff0c;如 images and text。 列表支持多种交互&#xff0c;包括滑动项目以显示选项、拖动以重新排列列表中的项目以及删除…

MySQL表的增删改查(进阶)

目录 数据库约束 约束的定义 约束类型 null约束 unique:唯一约束 default:默认值约束 primary key:主键约束(重要) foreign key:外键约束(描述两个表之间的关联) 表的设计 一般思路 三大范式 一对一 一对多 ​编辑 多对多 ​编辑 新增 查询 聚合查询 聚合函…

Ridgeline plot / 远山图 / 山脊图 怎么画?怎么优化?

工具 Origin 2022 当然&#xff0c;用Matlab、Python也是可以的。 颜色配置 色卡调整

GEE:将鼠标变成十字指针,点击获取影像值,显示值到UI中

作者&#xff1a;CSDN _养乐多_ 本文记录了在 Google Earth Engine&#xff08;GEE&#xff09;开发中&#xff0c;将鼠标变成十字指针&#xff0c;点击获取影像值&#xff0c;显示值到UI中的代码片段。这段代码复制过去修改变量名就可以用了。 效果如下图所示&#xff0c; …

Transformer详解一:transformer的由来和先导知识

目录 参考资料前言一、预训练二、神经网络语言模型&#xff08;NNLM&#xff09;&#xff1a;预测下一个词one-hot编码的缺陷词向量&#xff08;word embedding&#xff09; 三、Word2Vec模型&#xff1a;得到词向量CBOWSkip-gramWord2Vec和NNLM的区别Word2Vec的缺陷 四、ELMO模…

Python---练习:把8名讲师随机分配到3个教室

案例&#xff1a;把8名讲师随机分配到3个教室 列表嵌套&#xff1a;有3个教室[[],[],[]]&#xff0c;8名讲师[A,B,C,D,E,F,G,H]&#xff0c;将8名讲师随机分配到3个教室中。 分析&#xff1a; 一步步来解决。 首先&#xff0c; 要求有3个教室&#xff0c;第一间教室、第二间…

微信小程序真机调试连接状态一直在正常和未链接之间反复横跳?

背景&#xff1a;小程序真机调试的时候&#xff0c;发现真机的network不显示接口调用情况&#xff0c;控制台也没有输出内容。具体如下所示&#xff1b; 解决方法&#xff1a; 1、确保手机端连接的网络和微信开发者工具网络一致&#xff0c;比如用同一个WiFi 2、真机自动调试…

Ubuntu 22.04源码安装cmake 3.27.7

安装参考博客是《ubuntu安装cmake》和《Ubuntu 安装CMake》。 https://cmake.org/download是cmake官网下载的网址。 sudo wget -c https://github.com/Kitware/CMake/releases/download/v3.27.7/cmake-3.27.7.tar.gz可以下载源码&#xff0c;最后显示‘cmake-3.27.7.tar.gz’…

leetcode刷题 - SQL - 中等

1. 176. 第二高的薪水 筛选出第二大 查询并返回 Employee 表中第二高的薪水 。如果不存在第二高的薪水&#xff0c;查询应该返回 null(Pandas 则返回 None) 。查询结果如下例所示。 666中等的第一题就上强度 强行解法 select max(salary) as SecondHighestSalary from Emp…

Allegro层叠中的Etch Factor-铜皮的腐蚀因子如何计算

Allegro层叠中的Etch Factor-铜皮的腐蚀因子如何计算 在用Allegro进行PCB设计的时候,Cross-section中需要填入对应的信息,一般填入每层的厚度即可,如下图 当PCB需要进行仿真分析的时候,Etch-Factor这个值是必须要填写的,如下图 目前看到的都是90这个值,这是一个理论值。 …

c语言实现两个有序链表的合并

合并两个有序链表是c语言数据结构中比较经典的问题&#xff0c;首先两个链表都是有序的&#xff0c;即节点的顺序是按照各个节点中的值从小到大排序&#xff0c;而且合并之后的新链表中的各个节点顺序也要满足从小到大的排序&#xff0c;具体如下图所示。 思路&#xff1a;用ma…

Java的类与Golang的结构体的区别

Java作为一门面向对象&#xff08;OOP&#xff09;的编程语言&#xff0c;它有类&#xff08;class&#xff09;的存在&#xff0c;而对于Golang&#xff0c;它不完全遵从OOP编程语言的设计思想&#xff0c;但它也有类似Java类的结构存在&#xff0c;那就是结构体&#xff08;s…

宝塔开心版hostcli的广告去除

首先感谢hostcli把宝塔7.6剥离了&#xff0c;直接安装我这里是缺少pyenv的包。 直接进入正题吧。 定位到页面左下方的广告位于 /www/server/panel/BTPanel/templates/default/layout.html “退出”按钮下方有条线开始去掉 去掉之前的忘了截图了&#xff0c;就这样吧&#xff…

【数据结构】反射、枚举

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈数据结构 &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 反射、枚举 1. 反射1.1 定义1.2 反射…