作业1: Web服务器

问题描述

使用Python开发一个简单的Web服务器,它仅能处理一个请求,具体而言,你的服务器将

    • 当一个客户(浏览器)联系时创建一个连接套接字;


    • 这个连接套接字接受http请求;


    • 解释该请求以确定所请求的特定文件;


    • 从服务器的文件系统获得请求的文件;


    • 创建一个由请求的文件组成的HTTP响应报文,报文前有首部行;


  • 经TCP连接向请求的浏览器发送响应; 如果文件不存在,返回404 Not Found

问题解决

服务端代码

 1from socket import *
 2serverSocket = socket(AF_INET, SOCK_STREAM)
 3serverSocket.bind(("127.0.0.1",9999))
 4serverSocket.listen(1)
 5# 没有客户端链接时一直在此阻塞
 6connectionSocket, addr = serverSocket.accept()
 7while True:
 8    print('waiting for connection...')
 9    try:
10        #接收1k数据
11        data = connectionSocket.recv(1024)
12        print(data)
13        if not data:
14            continue
15        #data是一个get的http请求报文
16        filename = data.split()[1] #filename = /HelloWorld.html
17        # #print(filename[1:])
18        f = open(filename[1:],encoding="utf-8") #f = HelloWorld.html
19        outputdata = f.read()
20        header = 'HTTP/1.1 200 OK\r\n\r\n'
21        #回复报文
22        connectionSocket.send(header.encode())
23        for i in range(0, len(outputdata)):
24            connectionSocket.send(outputdata[i].encode())
25        #connectionSocket.close()
26
27    except IOError:
28        header = 'HTTP/1.1 404 NOT FOUND\r\n\r\n'
29        connectionSocket.send(header.encode())
30        connectionSocket.close()
31# 浏览器键入 localhost:***/index.html会有两个请求
32# index.html && favicon.ico(网站的图标)

客户端代码

 1from socket import *
 2ClientSocket = socket(AF_INET, SOCK_STREAM)
 3ClientSocket.connect(('localhost',9999))
 4while True:
 5    #这里的Connetction: close不同于浏览器常见的keep-alive,
 6    #close表示要求服务器在发送完被请求的对象后就关闭这条链接
 7    Head = '''GET /index.html HTTP/1.1\r\nHost: localhost:9999\r\nConnection: close\r\nUser-agent: Mozilla/5.0\r\n\r\n'''
 8    ClientSocket.send(Head.encode('utf-8'))
 9    data = ClientSocket.recv(1024)
10    print(data)
11    with open("response.html","wb") as f:
12        f.write(data)

How to run

  • 首先运行服务端代码WebServer.py

  • 再者,可以直接运行WebClient.py,此时会在工程路径下得到一个响应文件response.html 也可以在浏览器输入localhost:9999/index.html,将在网页上看到结果。在这里插入图片描述

计算机网络自顶向下方法套接字编程之python实现_Python

作业2: UDP ping程序

问题描述

使用python采用UDP协议编写一个ping程序,发送一个简单的ping报文给服务器,并确定从客户发送ping报文服务器到接受到pong报文为止的时延,称为往返时延(RTT) 。
因为UDP是一个不可靠的协议,客户发送的分组可能会丢失,为此,客户不能无限期地等待服务器的响应,等待时间至多为1s,否则,打印一条错误信息。

问题解决

服务端代码

 1import random
 2from socket import *
 3#AF_INET指定使用IPv4协议,如果要用更先进的IPv6,就指定为AF_INET6
 4#SOCK_DGRAM指定了这个Socket的类型是UDP
 5serverSocket = socket(AF_INET, SOCK_DGRAM)
 6#用0.0.0.0绑定到所有的网络地址,还可以用127.0.0.1绑定到本机地址
 7serverSocket.bind(('127.0.0.1',12000))
 8
 9while True:
10    #产生一个0到10之间的随机数
11    rand = random.randint(0, 10)
12    #从套接口上读取数据,参数为缓冲区大小
13    message, address = serverSocket.recvfrom(1024)
14    #通过打印我们可以看到UDP客户端socket的端口是不确定,系统随机分配的
15    print("收到来自 %s 的报文: (%s)" % (address,message))
16    # 把接收到的信息全部转为大写
17    print("随机数是: %d" % rand)
18    message = message.upper()
19    #如果随机数小于4,服务端无应答,客户端就会超时
20    if rand < 4:
21        continue
22    serverSocket.sendto(message, address)

客户端代码

 1import time
 2from socket import *
 3serverName = '127.0.0.1' # 主机
 4serverPort = 12000
 5# 创建Socket时,AF_INET指定使用IPv4协议,如果要用更先进的IPv6,就指定为AF_INET6
 6# SOCK_DGRAM指定了这个Socket的类型是UDP
 7# SOCK_STREAM指定使用面向流的TCP协议
 8clientSocket = socket(AF_INET, SOCK_DGRAM)
 9clientSocket.settimeout(1) # 设置超时时间为1s
10for i in range(0, 10):
11    oldTime = time.time()
12    sendTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(oldTime))
13    # encode()把str转成bytes,传输格式要求
14    message = ('package %d,client_local_time:%s' % (i + 1, sendTime)).encode()
15    try:
16        # 发送数据
17        clientSocket.sendto(message, (serverName, serverPort))
18        # 1024指定要接收的最大数据量为1kb = 1024 bytes
19        # recvfrom是一个系统调用,由用户态转向系统态,从套接口上接收数据,并捕获数据发送源的地址。
20        # 如果数据报大于缓冲区,那么缓冲区中只有数据报的前面部分,其他的数据都丢失了,并且recvfrom()函数返回WSAEMSGSIZE错误
21        # 如果没有数据待读,那么除非是非阻塞模式,不然的话套接口将一直等待数据的到来,果没有在Timeout = 1s内接收到数据,此时将返回SOCKET_ERROR错误,错误代码是WSAEWOULDBLOCK。用select()或WSAAsynSelect()可以获知何时数据到达
22        # UDP的 recvfrom() 和 TCP 的recv()不一样,具体可以看 TCP Ping项目
23        modifiedMessage, serverAddress = clientSocket.recvfrom(1024)
24        # 计算往返时间
25        rtt = time.time() - oldTime
26        # decode 把bytes转成str
27        modifiedMessage = modifiedMessage.decode("utf-8")
28        print('报文 %d 收到来自 %s 的应答: %s,往返时延(RTT) = %fs' % (i+1, serverName,modifiedMessage, rtt))
29    except Exception as e:
30        print('报文 %d: 的请求超时' % (i+1)) # 处理异常

How to Run

先运行服务端代码,再运行客户端代码,注意不要占用端口。在这里插入图片描述

计算机网络自顶向下方法套接字编程之python实现_Python_02

邮件客户

问题描述

使用STMP协议从一个邮箱向另一个邮箱发送邮件

问题解决

可以先百度了解一下:Windows下操作POP3

主要代码

 1#作业3:邮件客户
 2from smtplib import SMTP
 3from email.mime.text import MIMEText
 4from email.header import Header
 5
 6mail_server = 'smtp.163.com'
 7#根据发送方邮箱确定邮箱服务器
 8#qq邮箱的服务器为smtp.qq.com;163邮箱为smtp.163.com
 9def get_mail_server(sender):
10    key = sender[sender.index('@')+1:]
11    return "smtp."+key
12
13port = '25'  ## SMTP协议默认端口是25
14sender = '2391527690@qq.com'
15mail_server = get_mail_server(sender)
16sender_pass = 'put your mail_code here'    #注意是授权码,而不是登录密码,需要在邮箱端先获取
17receiver = 'csu_xiaotao@163.com'
18mail_msg = 'this is a demo'
19
20#第一个参数就是邮件正文,
21# 第二个参数是MIME的subtype,传入'plain'表示纯文本,最终的MIME就是'text/plain',
22# 最后一定要用utf-8编码保证多语言兼容性。
23msg = MIMEText(mail_msg, 'plain', 'utf-8')
24msg['From'] = sender
25msg['To'] = receiver
26#Header对象编码文本,包含utf-8编码信息和Base64编码。
27msg['Subject'] = Header('来自inspurer的个人计算机', 'utf-8')
28try:
29    server = SMTP(mail_server, port)
30    #用set_debuglevel(1),可以打印出和SMTP服务器交互的所有信息
31    #server.set_debuglevel(1)
32    server.login(sender, sender_pass)
33    #由于可以一次发给多个人,所以传入一个list,邮件正文是一个str,as_string()把MIMEText对象变成str
34    server.sendmail(sender, (receiver), msg.as_string() )
35    server.quit()
36    print("邮件发送成功!")
37except:
38    server.quit()
39    print("邮件发送失败!")

How to Run

直接运行stmpDemo.py,注意代码里的邮箱授权码要填成你自己的,它和邮箱登录密码不一样,至于怎么获取百度吧,我不做搬运工  在这里插入图片描述

计算机网络自顶向下方法套接字编程之python实现_Python_03

计算机网络自顶向下方法套接字编程之python实现_Python_04

在这里插入图片描述

计算机网络自顶向下方法套接字编程之python实现_Python_05