2018.8.6
目录
day01
网络编程 3
进程线程 3.5
网络 + 进程线程 1.5
MongoDB 4
regex 1.5
项目编程 2.5
难点:IO多路复用
项目编写
多任务编程理解
网络编程
网络目的:数据传输
ISO(国际化标准化组织)
OSI七层模型...》 网络通信的标准化流程
- 应用层:提供用户服务,具体的内容由特定的程序规定
- 表示层:提供数据的加密和压缩优化
- 会话层:确定建立应用连接,选择传输服务
- 传输层:提供数据传输服务,进行流量控制
- 网络层:路由选择,网络互联
- 链路层:提供链路交换,具体的消息发送
- 物理层:物理硬件,接口,网卡的规定
四层模型
- 应用层
- 传输层
- 网络层
- 物理链路层
五层模型(TCP/IP模型)
- 应用层(应用层 表示层 会话层)
- 传输层
- 网络层
- 链路层
- 物理层
OSI模型优点:将功能分开,降低网络传输中的耦合度,使开发流程更加清晰,每部分各司其职
高内聚:每个模块功能尽量单一,不会多个功能掺杂
低耦合:尽量降低每个模块之间的关联系
要求:能够顺序说出七层模型,五层模型,知道每一层干什么事情,理解消息传输流程
网络协议:在网络通信中协议各方必须遵守的规定,如建立什么连接,消息结构如何解析等
5层模型 | 对应的协议 |
---|---|
应用层 | TFTP HTTP DNS SMTP |
传输层 | TCP UDP |
网络层 | IP |
物理层 | IEEE |
网络相关概念
网络主机:在网络上确定一台主机
- 网络主机:在网络上确定一台主机
- 本地使用:'localhost' 127.0.0.1
- 网络地址:'0.0.0.0' '172.60.50.54' (本机网络IP)
- 查看本机IP地址:ifconfig (linux)
ipconfig (windows) - ipython3 进入交互模式
-
通过计算机名获取匹配的IP
In [5]: socket.gethostbyname('tedu')
Out[5]: '127.0.1.1'In [6]: socket.gethostbyname('localhost')
Out[6]: '127.0.0.1' -
获取计算机名:
In [2]: socket.gethostname()
Out[2]: 'tedu'
IP地址
-
在网络上确定一台主机的地址
-
IPv4 :点分十进制 比如 192.168.1.72 0–255
32位二级制表示 -
IPv6 : 128位二进制
-
网络连接测试
ping 172.60.50.60
特殊IP
特殊ip | 表示意思 |
---|---|
127.0.0.1 | 本地测试IP |
0.0.0.0 | 使用局域网内可用的IP |
192.168.1.0 | 表示当前网段 |
192.168.1.1 | 通常是网络节点设备的IP (网关) |
192.168.1.255 | 广播地址 |
通过域名获取服务器信息
socket.gethostbyaddr('www.baidu.com')
('127.0.0.1', [], ['119.75.213.61'])
主机 主机别名 主机IP
将点分十进制IP转换为二进制
In [11]: socket.inet_aton('192.168.1.2')
Out[11]: b'\xc0\xa8\x01\x02'
二进制转换为点分十进制IP
In [12]: socket.inet_ntoa(b'\xc0\xa8\x01\x02')
Out[12]: '192.168.1.2'
域名:
-
定义: 网络服务器地址的网络名称
-
端口号 : 端口号是网络地址的一部分,在一个系统中 每个网络应用都会有一个端口号相对应。用来在接收消息时确定由谁来接收
-
范围 : 1–65535
1–255 一些通用的众所周知程序占用
256-1023 系统应用端口
1024 — 65535 自用 >10000 -
获取应用端口
In [1]: import socket In [2]: socket.getservbyname('mysql') Out[2]: 3306 In [3]: socket.getservbyname('http') Out[3]: 80 In [4]: socket.getservbyname('ssh') Out[4]: 22
-
传输层服务
1,面向连接的传输服务 ---》tcp协议
- 传输特征:
- 可靠的数据传输
- 可靠性:数据在传输中,无失序,无差错,无丢失,无重复
- 在数据传输前和传输结束后需要建立连接和断开连接
- 三次握手:在面向连接的传输服务中建立连接的过程
- 客户端向服务器发送连接请求
- 服务器接收到请求进行确认,返回确认报文
- 客户端收到服务器回复最终确认连接
- 四次挥手:在面向连接的传输服务中断开连接的过程
- 主动方发送报文,告知被动方要断开连接
- 被动方回复报文,表示已经接收到请求,准备断开
- 被动方再次发送报文,表示准备处理就绪,可以断开
- 主动方发送确认报文,断开连接
- 应用情况:适用于传输较大的内容或文件,网络良好,需要保证传输可靠性的情况
- e.g.: 聊天信息,文件的上传下载,邮件处理,网页获取
2,面向无法连接的传输服务 ---》udp协议
传输特点:
- 不保证传输的可靠性
- 没有连接和断开的过程
- 数据的首发比较自由
- 适用情况可能产生丢包,对传输可靠性要求低
e.g.:网络视频,群聊,广播等
要求:
- 理解三次握手和四次挥手,能够描述过程
- 直到tcp和udp传输的区别
socket 套接字编程
- 目的
通过编程语言提供的套接字编程接口,可以更简单的完成基于tcp和udp的编程 - 套接字:完成上述目标的一种编程方法
- 套接字类别
- 流式套接字(SOCK_STREAM):传输层基于tcp的协议通信
面向连接可靠的传输 tcp的传输 流式套接字 - 数据报套接字(SOCK_DGRAM):传输层基于udp协议传输
面向无连接不可靠的传输 udp的传输 数据报套接字 - 底层套接字(SOCK_RAM):访问底层协议套接字
- 流式套接字(SOCK_STREAM):传输层基于tcp的协议通信
TCP的服务端
import socket
1,创建套接字
- socket.socket(sock_family=AF_INET,
- sock_type = SOCK_STREAM,
- proto = 0)
功能:创建套接字
参数:
- sock_family 地址族类型, AF_INET ipv4网通通信
- sock_type 套接字类型,SOCK_STREAM 流式, SOCK_DGRAM 数据报
- proto 通常为0 选定子协议类型
返回值:返回套接字对象
2,绑定地址
- sockfd.bind(addr)
- 功能:绑定地址
- 参数:addr ---》元组(ip,port)('0.0.0.0',1234)(ip,端口号)
一个元组包含两项 ,第一项为IP第二项为端口号 ,(’172.60.50.50’,8888)
3,设置监听套接字
- sockfd.listen(n)
- 功能:将套接字设置为监听套接字,创建监听队列
- 参数:n是一个正整数 表示监听等待队列的大小
- *一个监听套接字可以连接多个客户端
4,等待接受客户端连接
- connfd,addr = sockfd.accept()
- 功能:阻塞等待处理客户端连接
- 返回值:coonnfd 新的套接字,用于与客户端通信
- addr 连接的客户端的地址(ip,port)
- *阻塞函数:当程序运行到阻塞函数位置,如果某种条件没有达成则暂停程序运行,直到条件达成结束阻塞
5,消息的收发
- data = connfd.recv(buffersize)
- 功能 :接收消息
- 参数 : 一次最多接收多大的消息 字节
- 返回值 : 返回接收到的内容
- n = connfd.send(data)
- 功能 : 发送消息
- 参数 : 要发送的内容 要求bytes格式
- 返回值 : 返回实际发送的字节数
6,关闭套接字
- sockfd.close()
- 功能:关闭套接字 tcp套接字连接断开
- telnet ip port
from socket import *
#创建套接字
sockfd = socket(AF_INET,SOCK_STREAM)
#绑定地址
sockfd.bind(('127.0.0.1',8888))
#设置监听
sockfd.listen(5)
#等待客户端连接
print("Waiting for connect...")
connfd,addr = sockfd.accept()
print("Connect from",addr)
#消息收发
data = connfd.recv(1024)
print("Receive:",data.decode())
n = connfd.send(b"Receive your message")
print("send %d bytes"%n)
#关闭套接字
connfd.close()
sockfd.close()
TCP的客户端
- 创建套接字(和服务端套接字类型相同)
- 发起连接
- 格式:connect(addr)
- 功能:向服务端发起连接
- 参数:服务端地址 元组
- 消息收发
- 关闭套接字
- recv() 特性
- 如果连接双方断开连接,则recv会立即结束阻塞返回空字符串
- 当接收缓冲区为空的时候会阻塞
- 如果recv一次接收不完缓存去内容,下一次会继续接收
- send()特性
- 如果一段不存在,另一端还在试图send操作时会产生BrokenPipeError异常
- 当发送缓冲区慢的时候会阻塞
- 网络收发缓冲区
- 发送和接收消息均先放到缓冲区中,在进行处理
即 recv和send实际是从缓冲区接收内容,向缓冲区发送消息
- 发送和接收消息均先放到缓冲区中,在进行处理
from socket import *
#创建套接字
sockfd = socket()
#发起连接
sockfd.connect(('127.0.0.1',8888))
#消息收发
msg = input("Msg>>")
sockfd.send(msg.encode())
data = sockfd.recv(1024)
print(data.decode())
sockfd.close()
作业:
1,将要求内容整理话术回答
2,将tcp交互程序改写可以连续的收发消息
from socket import *
#创建套接字
sockfd = socket(AF_INET,SOCK_STREAM)
#绑定地址
sockfd.bind(('127.0.0.1',9999))
#设置监听
sockfd.listen(5)
while True:
#等待客户端连接
print("Waiting for connect...")
connfd,addr = sockfd.accept()
print("Connect from",addr)
while True:
#消息收发
data = connfd.recv(1024)
if not data:
break
print("Receive:",data.decode())
n = connfd.send(b"Receive your message")
print("send %d bytes"%n)
#关闭套接字
connfd.close()
sockfd.close()
from socket import *
#创建套接字
sockfd = socket()
#发起连接
sockfd.connect(('127.0.0.1',9999))
while True:
#消息收发
msg = input("Msg>>")
if not msg:
break
sockfd.sendall(msg.encode())
data = sockfd.recv(1024)
print(data.decode())
sockfd.close()