网络编程
软件开发架构
c/s架构
即Client和Server -----> 客户端和服务器端架构
B/S架构
即Browser和Server ----> 浏览器端和服务器端架构
什么是网络
网络就是一种辅助双方或者多方能够连接在一起的工具。
TCP/IP
伴随着网络发展,人们使用了很多同学方式,有些已不再使用,现在使用最广泛的是TCP/IP(Transmission Control Protocol/ Internet Protocol).
TCPMP是标准的协议,其可以使世界范围内计算机通过Internet或本地网络通信。
目的
- 使用网络把多方连接在一起,然后,进行数据传输
- 为了让不同电脑的软件可以互相传递数据,借助网络的功能。
网络编程的定义
让不同电脑中软件能够进行数据传递,即网络中不同主机进程间的通信。
IP地址分类
目前IP主要分为两种
- ipv4, 32位二进制构成 分成四段,每段范围0-255(2的8次方,四个字节)
- ipv6, 128位二进制构成
每一个IP包含两部分:
- 网络号
- 主机号
类似电话号码由区号+电话主机号组成
进制
二进制(binary,bin)
八进制(Octal,oct)
十进制(decimal,int)
十六进制(Hexadecimal,hex)
- MAC地址:在设备与设备之间数据通信时用来标记收发双方(网卡的序列号)
- IP地址:在逻辑上标记一台电脑,用来指引数据包的收发方向(相当于电脑的序列号)
- 网络掩码:用来区分ip地址的网络号和主机号
- 默认网关:当需要发送的数据包的目的ip不在本网段内时,就会发送给默认的一台电脑,成为网关
- 集线器:已过时,用来连接多态电脑,缺点:每次收发数据都进行广播,网络会变的拥堵
- 交换机:集线器的升级版,有学习功能知道需要发送给哪台设备,根据需要进行单播、广播
- 路由器:连接多个不同的网段,让他们之间可以进行收发数据,每次收到数据后,ip不变,但是MAC地址会变化
- DNS:用来解析出IP(类似电话簿)
- http服务器:提供浏览器能够访问到的数据
开放式系统互联参考模型
(Open System Interconection Reference Model)
在OSI中,网络体系结构被分成下面的七层。
- 物理层
- 定义了通信设备的传输规范,规定了激活、维持和关闭通信节点之间的机械特性、电气特性和功能特性等。此层为上层协议提供了一个传输数据的物理媒介。
- 数据链路层
- 定义了数据封装以及传送的方式。这个层次的数据单位称为“帧”。数据链路层包括两个重要的子层:逻辑链路控制层(Logic Link Control,LLC)和介质访问控制层(Media Access Control,MAC)。LLC用来对节点间的通信链路进行初始化,并防止链路中断,确保系统的可靠通信。而MAC则用来检测包含在数据帧中的地址信息。这里的地址是链路地址或物理地址,是在设备制造的时候设置的。网络上的两种设备不能有相同的物理地址,否则会造成网络信息传送失败。
- 网络层
- 定义了数据的寻址和路由方式。这一层负责对子网间的数据选择路由,并实现网络互连等功能。
- 传输层
- 为数据提供端到端传输。这是比网络层更高的层次,是主机到主机的层次。传输层将对上层的数据进行分段并进行端到端传输。另外,还提供差错控制和流量控制机制。
- 会话层
- 用来为通信的双方制定通信方式,包括建立和拆除会话。另外,此层将会在数据中插入校验点来实现数据同步。
- 表示层
- 为不同的用户提供数据和信息的转换。同时还提供解压缩和加解密服务。这一层保证了两个主机的信息可以互相理解。
- 应用层
- 控制着用户绝大多数对于网络应用程序的访问,提供了访问网络服务的接口。
端口
整个网络通信通过IP地址+端口来标识不同的网络服务。
端口号是用来表示区别网络中的应用,操作系统会对端口进行编号,即端口号。
- 端口号使用16位,也就是2个字节的数字来标识,范围0-2^16-1,0-65535
端口的分配是基于一定规则的,而不是随意分配的。
知名端口
- 80,分配给http服务的
- 21,分配给ftp服务
动态端口(Dynamic Ports)
一般不固定分配某种服务,动态分配。范围:1024-65535
所谓的动态分配,是指一个程序需要网络通信时,它向主机申请一个端口,主机从可以的端口号中分配一个供其使用。关闭程序时,同时释放占用的端口。
Socket简介
socket(简称 套接字
) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的例如我们每天浏览网页、QQ 聊天、收发 email 等等
不同电脑上进程的标识和识别用唯一标识来标记一个进程。在电脑上,可以通过用进程号(pid)来唯一标识进程。但是在网络上,不可以。需要利用TCP/IP协议来帮助我们解决问题。
创建socket
在 Python 中 使用socket 模块的函数 socket 就可以完成:
socket.socket(AddressFamily, Type)
函数 socket.socket 创建一个 socket,返回该 socket 的描述符,该函数带有两个参数:
- Address Family:可以选择 AF_INET(用于 Internet 进程间通信) 或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
- Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)
创建一个tcp socket(tcp套接字)
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket Created'
#主机名
host = socket.gethostname()
#端口名
port = 9999
#绑定端口
serversocket.bind((host,port))
#设置最大连接数,超过后排队
serversocket.listen(5)
While True:
#简历客户端连接
client
创建一个udp socket(udp套接字)
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print 'Socket Created'
UDP网络程序
udp----->User Datagram Protocal(用户数据协议)是一个无连接的简单的面向数据报的运输层协议
优点:
- 优点
- 传输速度快(UDP在传输时无需在客户端和服务器端之间建立连接,也无超时重新发送机制)
- 缺点:
- 不提供可靠性(UDP是一种面向无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。)
- 特点
- UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送。 UDP传输数据时有大小限制,每个被传输的数据报必须限定在64KB之内。 UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。
UDP一般多用于多点通信和实时的数据业务。比如:视频、qq、语音广播等
发送数据
创建一个udp客户端程序的流程是简单,具体步骤如下:
- 创建客户端套接字
- 发送/接收数据
- 关闭套接字
socket和file的区别
- file针对指定模块进行“打开”,“读写”,“关闭”
- socket针对服务端和客户端socket进行“打开”,“读写”,“关闭”
总结:
- 一个udp网络层,可以不绑定端口,此时系统会自动分配一个端口。重新运行此程序,端口号可能会发生变化
- 一个udp网络程序,可以绑定信息(IP, Ports)。如果绑定成功,那么操作系统用这个端口号来进行区别收到的网络数据是否是次进程的。
TCP
简介:TCP协议,传输控制协议(Transmission Control Protocol),是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP通信需要经过创建连接、传输数据、终止连接三个步骤
TCP和UDP的不同点
- 面向连接
- 有序的数据传输
- 无差错的数据传输
- 阻塞/流量控制
- TCP通信模型,类似“打电话”,在通信开始之前,一定要先建立相关的链接,才能发送数据;而udp通信模型中,在通信开始之前,不需要建立相关的链接,只需要发送数据即可。
在python中,用TCP进行socket编程也比较简单。
- 客户端
- 要主动连接服务器的ip和服务器的指定端口
- -服务器
- 监听指定端口
- 对于每一个新的连接,创建一个线程或者进程。
通常,服务器程序可以无限运行下去。要注意的是,一个端口不能同时被两个socket绑定。
TCP服务端和客户端格子socket的创建和交互。
tcp服务器
在Python程序中,如果要完成一个tcp服务器的功能,需要的流程如下:
1.socket创建一个套接字(买手机)
2.bin()绑定一个套接字(插卡)
3.listen()使套接字由主动变成被动连接,即开启监听模式(设置一个响铃)
4.accept()等待客户端的连接
5.关闭和客户端交互的套接字
6.关闭和客户端交互的套接字
7.关闭监听套接字
创建服务器
from socket import *
# 创建socket
tcpSerSocket = socket(AF_INET, SOCK_STREAM)
# 绑定本地信息
address = ('', 7788)
tcpSerSocket.bind(address)
# 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的链接了
tcpSerSocket.listen(5)
# 如果有新的客户端来链接服务器,那么就产生一个新的套接字专门为这个客户端服务器
# newSocket用来为这个客户端服务
# tcpSerSocket就可以省下来专门等待其他新客户端的链接
newSocket, clientAddr = tcpSerSocket.accept()
# 接收对方发送过来的数据,最大接收1024个字节
recvData = newSocket.recv(1024)
print '接收到的数据为:',recvData
# 发送一些数据到客户端
newSocket.send("thank you !")
# 关闭为这个客户端服务的套接字,只要关闭了,就意味着为不能再为这个客户端服务了,如果还需要服务,只能再次重新连接
newSocket.close()
# 关闭监听套接字,只要这个套接字关闭了,就意味着整个程序不能再接收任何新的客户端的连接
tcpSerSocket.close()
创建客户端
#coding=utf-8
import socket
# 创建socket
tcpClientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 链接服务器
serAddr = input("请输入服务器IP:")
serPort = int(input("请输入服务器port:"))
tcpClientSocket.connect((serAddr, serPort))
# 提示用户输入数据
sendData = input("请输入要发送的数据:")
tcpClientSocket.send(sendData.encode("utf-8"))
# 接收对方发送过来的数据,最大接收1024个字节
recvData = tcpClientSocket.recv(1024)
print("接收到的数据为:", recvData.decode("gbk"))
# 关闭套接字
tcpClientSocket.close()
TCP协议 当应用程序希望通过TCP与另外一个应用程序通信时,他会发送一个通信请求。这个请求必须被送到一个确切的地址。在双方"握手"之后,TCP将在两个应用程序之间建立一个全双工(full-duplex)的通信。这个全双方的通信将占用两个计算机之间的通信线路,直到他被一方或者双方关闭为止。