一、简答题
1、简述TCP和UDP的区别以及优缺点
区别:
UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息。
TCP是面向连接的通信协议,通过三次握手建立连接,通讯完成时四次挥手。
TCP优缺点:
优点:在数据传递时,有确认、窗口、重传、拥塞控制机制,能保证数据正确性,较为可靠。
缺点:TCP相对于UDP速度慢一点、要求系统资源较多。
UDP优缺点:
优点:UDP速度快、操作简单、需要求系统资源较少,由于通讯不需要连接,可以实现广播发送
缺点:传送数据前并不与对方建立连接,对接收到的数据也不发送确认信号,发送端不知道数据是否会正确接收,也不用重发,不可靠。
2、函数装饰器有什么作用请列举出至少三个并举出一些实例
装饰器的作用:
装饰器本质上是一个python函数,它可以在让其他函数在不需要做任何代码的变动的前提下增加额外的功能,
装饰器的返回值也是一个函数的对象,它经常用于有切面需求的场景,
比如:插入日志、性能测试、事务处理、缓存、权限的校检等场景。
有了装饰器就可以抽离出大量的与函数功能本身无关的的雷同的代码并发并继续使用。
装饰器的实例:
无参数的函数
1. from time import ctime, sleep
2.
3. def timefun(func):
4. def wrapped_func():
5. print("%s called at %s" % (func.__name__, ctime()))
6. func()
7. return wrapped_func
8.
9. @timefun
10.def foo():
11. print("I am foo")
12.
13.foo()
14.sleep(2)
15.foo()
3、简答浏览器通过WSGI请求动态资源的过程
1. http请求动态资源
2. 通过wsgi调用一个属性
3. 通过引用调用web服务器的方法,设置返回的状态和头信息
4. 调用返回,此时web服务器端保存了刚刚设置的信息
5. 查询数据库等,生成动态页面的body信息
6. 把生成的body信息返回给web服务器的调用
7. web服务器把数据返回给浏览器
4、描述用浏览器器访问www.baidu.com的过程
baidu.com ip先要解析出对应的地址
- 要先使用arp获取默认网关的mac地址
- 组织数据发送给默认网关(ip还是dns服务器的ip,但是mac地址是默认网关的mac地址)
- 默认网关拥有转发数据的能力,把数据转发给路由器
- 路由器根据自己的路由协议,来选择一个合适的较快的路径转发数据给目的网关
- 目的网关(dns服务器所在的网关),把数据转发给dns服务器
- dns服务器查询解析出baidu.com对应的ip地址,并原路返回请求这个域名的
得到了baidu.com对应的ip地址之后,会发送tcp的3次握手,进行连接
- http使用协议发送请求数据个web服务器
- web服务器收到数据请求之后,通过查询自己的服务器得到相应的结果,原路返回给浏览器
- 浏览器接收到数据之后通过浏览器自己的渲染功能来显示这个网页
- 浏览器关闭tcp连接,即4次挥手结束,完成整个访问过程。
二、代码题
1、匹配下列文本y中的每个的邮箱
y=’123@qq.comaaa@163.combbb@126.comasdfasfs33333@adfcom’
1. import re
2.
3. match_obj = re.findall(r"[a-zA-Z0-9]+@[a-zA-Z0-9]+\.com",y)
4. for i in match_obj:
5. print(i)
2、编写一个TCP服务器把客户端发送的信息返回给改客户端
1. import socket
2.
3. if __name__ == '__main__':
4. server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
5. server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
6. server_socket.bind(("", 8888))
7. server_socket.listen(128)
8. client_socket, ip_port = server_socket.accept()
9. recv_data = client_socket.recv(1024)
10. print("收到客户端的数据:", recv_data.decode("gbk"))
11. send_content = recv_data.decode("gbk")
12. client_socket.send(send_content.encode("utf-8"))
13. client_socket.close()
14. server_socket.close()
3、使用装饰器装饰一个函数,计算这个函数从开始到结束的运行时间。
提示:可以使用time模块。
1. import time
2.
3. def timing(func):
4. def inner(*args, **kwavgs):
5. start = time.time()
6. func(*args, **kwavgs)
7. end = time.time() - start
8. print(end)
9. return inner
10.
11.@timing
12.def myFunc(*args, **kwargs):
13. for i in range(100000):
14. pass
15.
16.if __name__ == "__main__":
17. myfunc()
4、以下代码为TCP 并发服务器的部分,请在分别修改run_forever 函数 使满足以下要求
提示:选择性写出其中三个即可满分
(1) 多线程实现的并发服务器
(2) 多进程实现的并发服务器
(3) 协程实现的并发服务器
(4) 非阻塞、单线程-多路复用并发服务器
1. import socket
2. import threading
3. import multiprocessing
4. import gevent
5. from gevent import monkey
6. monkey.patch_all()
7.
8.
9. class WSGIServer(object):
10. def __init__(self, port):
11. self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
12. self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
13. self.tcp_server_socket.bind(("", 9988))
14. self.tcp_server_socket.listen(128)
15.
16. def run_forever(self):
17. while True:
18. client_socket, client_addr = self.tcp_server_socket.accept()
19. print("---一个新的客户端到来--->", client_addr)
20. # self.server_client(client_socket)
21. # 线程版本
22. threading.Thread(target=self.service_client(), args=(client_socket)).start()
23. # 进程版本
24. multiprocessing.Process(target=self.service_client(),args=(client_socket)).start()
25. # 协程版本
26. gevent.spawn(self.service_client, client_socket)
27.
28. def service_client(self, client_socket):# 这个函数是处理数据的函数
29. pass
30.
31.
32.def main():
33. """创建一个WSGI服务器"""
34. wsgi_server = WSGIServer(9988)
35. wsgi_server.run_forever()
36.
37.
38.
39.if __name__ == '__main__':
40. main()
三、三次握手与四次挥手
1、三次握手
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
2、四次挥手
第一步,当主机A的应用程序通知TCP数据已经发送完毕时,TCP向主机B发送一个带有FIN附加标记的报文段(FIN表示英文finish)。
第二步,主机B收到这个FIN报文段之后,并不立即用FIN报文段回复主机A,而是先向主机A发送一个确认序号ACK,同时通知自己相应的应用程序:对方要求关闭连接(先发送ACK的目的是为了防止在这段时间内,对方重传FIN报文段)。
第三步,主机B的应用程序告诉TCP:我要彻底的关闭连接,TCP向主机A送一个FIN报文段。
第四步,主机A收到这个FIN报文段后,向主机B发送一个ACK表示连接彻底释放。