假如有两个脚本foo.py , bar.py , 分别运行,都可以正常运行。但是现在想从两个程序之间传递一个数据。
C/S 即Client 和Server —> 客户端和服务器
B/S即Browser和Server —> 浏览器端和服务器端架构
网络就是一种辅助双方或者多方能够连接在一起的工具。
伴随着网络发展,人们使用了很多通信方法,有些已经不再使用,现在使用最广泛的是TCR/IP。
TCP/IP事实上是一些协议(protocols)的合集。当前大多数使用中的通信都使用TCP协议。
Internet是在一些共享的线路上发送数据’的。例如:在您的计算机上也许同时运行着几个应用程序,如Web浏览器、通讯软件等程序,而您只须通过一条单一的线路来连接互联网。上面所有的程序都共享这个连接,简单地说,用户往往不会觉察到这个共享的发生。
TCP/IP是标准协议,其可以使世界范围内的计算机通过Internet或本地网络通信。
- 如果两台电脑之间通过网线连接是可以直接通信的,但是需要提前设置好ip地址以及网络掩码
- 并且ip地址需要控制在同一网段内,例如 一台为
192.168.1.1
另一台为192.168.1.2
则可以进行通信
- 当有多台电脑需要组成一个网时,那么可以通过集线器(Hub)将其链接在一起
- 一般情况下集线器的接口较少
- 集线器有个缺点,它以广播的方式进行发送任何数据,即如果集线器接收到来自A电脑的数据本来是想转发给B电脑,如果此时它还连接着另外两台电脑C、D,那么它会把这个数据给每个电脑都发送一份,因此会导致网络拥堵
- 克服了集线器以广播发送数据的缺点,当需要广播的时候发送广播,当需要单播的时候又能够以单播的方式进行发送
- 它已经替代了之前的集线器
- 企业中就是用交换机来完成多态电脑设备的链接成网络的
较为复杂的通信过程如:www.baidu.com
- 在浏览器中输入一个网址时,需要将它先解析出ip地址来
- 当得到ip地址之后,浏览器以tcp的方式3次握手链接服务器
- 以tcp的方式发送http协议的请求数据 给 服务器
- 服务器tcp的方式回应http协议的应答数据 给浏览器
总结
让不同电脑 中的软件能够进行数据传递,即网络则不同主机进程间 的通信。
3、IP地址分类
目前Ip主要分为了、两种
每一个IP包含两部分;
类似电话号码由区号+电话主机号组成。
以太网适配器 以太网:
连接特定的 DNS 后缀 . . . . . . . :
IPv6 地址 . . . . . . . . . . . . : 2001:250:6405:6005:1844:28a9:321e:b17f
临时 IPv6 地址. . . . . . . . . . : 2001:250:6405:6005:96:3097:71bc:e1e9
临时 IPv6 地址. . . . . . . . . . : 2001:250:6405:6005:306b:8953:4b1e:dd61
本地链接 IPv6 地址. . . . . . . . : fe80::1844:28a9:321e:b17f%2
IPv4 地址 . . . . . . . . . . . . : 192.168.1.150
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : fe80::22a:6aff:fefa:ff3c%2
192.168.1.1
二进制基数:0,1
八:0-7
十:0-9
十六:0-9,ABCDEF(0-15)
二进制 | 八进制 | 十进制 | 十六进制 |
---|---|---|---|
0000 0001 | 0000 0001 | 1 | 0000 0001 |
0000 0010 | 0000 0002 | 2 | 0000 0002 |
0000 0011 | 0000 0003 | 3 | 0000 0003 |
0000 0100 | 0000 0004 | 4 | 0000 0004 |
0000 0101 | 0000 0005 | 5 | 0000 0005 |
0000 0110 | 0000 0006 | 6 | 0000 0006 |
0000 0111 | 0000 0007 | 7 | 0000 0007 |
0000 1000 | 0000 0010 | 8 | 0000 0008 |
0000 1001 | 0000 0011 | 9 | 0000 0009 |
0000 1010 | 0000 0012 | 10 | 0000 000A |
0000 1011 | 0000 0013 | 11 | 0000 000B |
0000 1100 | 0000 0014 | 12 | 0000 000C |
0000 1101 | 0000 0015 | 13 | 0000 000D |
0000 1110 | 0000 0016 | 14 | 0000 000E |
0000 1111 | 0000 0017 | 15 | 0000 000F |
进制基数为base
各进制到十进制的转化(X为每位上的数字,i为其位数)
二 —> 八,从右往左,三位一划
二 —> 十六,从右往左,四位一划
八到十六/十六到八
二进制作为桥梁,数位数
1111 1111 —> FF(十六) —> 377(八)
开放式系统互联参考模型(Open System Interconnection Reference Model)—> 简称OSI
这个标准定义了网络的七层框架,试图使得计算机在整个世界范围内实现互联。
在OSI中,网络体系结构被分成下面的七层。
按照分工不同把互联网协议从逻辑上划分了层级:
[外链图片转存失败(img-iiZbSHUN-1565008074578)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1564972004134.png)]
整个网络通信通过IP地址+端口来标识不同的网络服务。
端口号是用来表示区别网络中不同的应用,操作系统会对端口进行编号,即端口号。
端口号使用16位,也就是2个字节的数字来标识,范围0-2^16
端口的分配是基于一定规则的,而不是随意分配的。
知名端口
80,分配给HTTP服务的
21,分配给ftp服务的
动态窗口(Dynamic Ports)
一般不固定分配某种服务,动态分配。范围:1024-65535
所谓动态分配,是指一个程序需要网络通信时,它向主机申请一个端口,主机从可用的端口中分配一个供其使用。关闭程序时,同时释放占用的端口。
端 口查看:
netstat -ano
不同电脑上进程的标识与识别
用唯一标识来标记一个进程。
在电脑上,可以通过用进程号(PID)来唯一标识进程。但是在网络上,不可以。需要利用TCP/IP协议族来帮我们解决问题。
用IP可以唯一标识网络中的主机,协议+端口号唯一标识主机中的应用进程。
进程指的是,运行的程序以及运行程序用到的资源整体就称之为进程。
socket(套接字)是进程间通信的一种方式。
与其他进程通信的一个主要不同是:
它能不同主机间的进程间的通信。
现行大多数服务都是基于Socket来完成通信的。
比如:浏览网页,QQ聊天,收发Email等。
import socket
socket.socket(AddressFamily, Type)
参数说明:
创建一个TCP Socket
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.close()
server端
import socket
# 创建一个socket对象
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 主机名
host = socket.gethostname()
# 端口号
port = 9999
# 绑定端口
serversocket.bind((host, port))
# 设置最大连接数,超过后排队
serversocket.listen(5)
while True:
# 简历客户端连接
clientsocket, addr = serversocket.accept()
print("连接地址:\t %s" % (str(addr)))
msg = "网络编程测试。" + "\r\n"
clientsocket.send(msg.encode('utf-8'))
clientsocket.close()
client端
import socket
# 创建一个socket对象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# print(dir(s))
# 获取本地主机名
host = socket.gethostname()
# 设置端口号
port = 9999
# 连接服务,指定主机和端口
s.connect((host, port))
# 接收小于1024字节的数据
msg = s.recv(1024)
s.close()
print(msg.decode('utf-8'))
# 网络编程测试。
UDP —> User Datagram Protocol (用户数据报协议) 是一个无连接的简单的面向数据报的运输层协议。
UDP是面向无连接的通讯协议;
UDP包括目的端口号和源端口号信息,通讯不需要连接,能够实现广播发送。
UDP数据大小有限制,每个被传输的数据报必须限定64k以内。
UDP是一个不可靠的协议。发送出去的数据报不一定以相同的次序到达接收方。
UDP一般多用于多点通信,以及实时的数据业务。比如:
创建一个UDP客户端程序的流程:
1、创建一个客户端套接字
2、发送或接收数据
3、关闭套接字
socket和file的区别:
import socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
addr = ("192.168.1.112", 8345)
sendData = input("请输入要发送的数据:")
udp_socket.sendto(sendData.encode("gbk"), addr)
udp_socket.close()
import socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
Addr = ('192.168.1.112', 8345) # 目标IP
sendData = input("请输入要发送的数据:")
udp_socket.sendto(sendData.encode("utf-8"),Addr)
recvData = udp_socket.recvfrom(1024)
print(recvData)
udp_socket.close()
函数 | 描述 |
---|---|
服务器端套接字 | |
s.bind() | 绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址。 |
s.listen() | 开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。 |
s.accept() | 被动接受TCP客户端连接,(阻塞式)等待连接的到来 |
客户端套接字 | |
s.connect() | 主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。 |
s.connect_ex() | connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 |
公共用途的套接字函数 | |
s.recv() | 接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。 |
s.send() | 发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。 |
s.sendall() | 完整发送TCP数据,完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。 |
s.recvform() | 接收UDP数据,与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。 |
s.sendto() | 发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。 |
s.close() | 关闭套接字 |
s.getpeername() | 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。 |
s.getsockname() | 返回套接字自己的地址。通常是一个元组(ipaddr,port) |
s.setsockopt(level,optname,value) | 设置给定套接字选项的值。 |
s.getsockopt(level,optname[.buflen]) | 返回套接字选项的值。 |
s.settimeout(timeout) | 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect()) |
s.gettimeout() | 返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。 |
s.fileno() | 返回套接字的文件描述符。 |
s.setblocking(flag) | 如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。 |
s.makefile() | 创建一个与该套接字相关连的文件 |
用网络调试助手时,端口号会一直变动。
一般情况下,在一台电脑上运行的网络程序有很多,为了不与其他的网络程序占用同一个端口号,往往在编程中,udp的端口号一般不绑定。
但是如果需要做成一个服务器端的程序的话,是需要绑定的,想想看这又是为什么呢?
如果报警电话每天都在变,想必世界就会乱了,所以一般服务性的程序,往往需要一个固定的端口号,这就是所谓的端口绑定。
import socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
local_addr = ("", 7788) # IP地址和端口号,IP一般不用写,表示本地IP
udp_socket.bind(local_addr)
recv_data = udp_socket.recvfrom(1024)
print(recv_data[0].decode("gbk"))
udp_socket.close()
总结:
TCP协议,传输控制协议(Transmission Control Protocol),是一种面向连接的。可靠的,基于字节流的传输层通信协议。
TCP通信需要经过创建连接,传输数据,终止连接三个步骤。
通信双方必须先建立连接才能进行数据的传输,双方都必须为该连接分配必要的系统内核资源,以管理连接的状态和连接上的传输。
双方间的数据传输都可以通过这个连接进行。
完成数据交换后,双方断开此连接,以释放系统资源。
这种连接是一对一的
因此TCP不适用于广播的应用程序,基于广播的应用程序请使用UDP协议。
1)TCP采用发送应答机制
TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功
2)超时重传
发送端发出一个报文段之后就启动定时器,如果在定时时间内没有收到应答就重新发送这个报文段。
TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。
3)错误校验
TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
流量控制用来避免主机发送得过快而使接收方来不及完全收下。
在Python程序中,如果要完成一个TCP服务器的功能,需要的流程如下:
# tcp_server.py
import socket
# 创建套接字
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定本地信息
tcp_socket.bind(("", 8080)) # port num > 1024的随意用,< 1024的一般指定了用途
# 设置监听
tcp_socket.listen(5)
# 创建新的套接字
new_socket, addr = tcp_socket.accept()
# 收/发数据
content = new_socket.recv(1024)
print("接收到的数据:", content.decode("gbk"))
data = input("服务器发送的数据:")
new_socket.send(data.encode("gbk"))
# 关闭通信的socket
new_socket.close()
# 关闭用于监听的套接字
tcp_socket.close()
设置监听的目的:
socket默认为主动模式,listen() 能够将主动模式改为被动模式,被动了才能接收信息。
listen(5),5是指可以同时接收到的客户端申请的最大数,超过则拒绝连接。
创建新套接字的原因:
服务器接收到请求后,将生成一个新的套接字,专门给新来的客户端提供一对一的服务
此时,服务器套接字的任务就是,等待新的客户端套接字连接它。
# 客户端 tcp_client.py
import socket
# 创建套接字
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 目标服务器信息
server_ip = input("请输入服务器IP:")
server_port = int(input("请输入服务器port:"))
# 连接服务器
tcp_client_socket.connect((server_ip, server_port))
# 提示用户输入数据
send_data = input("请输入要发送的数据:")
tcp_client_socket.send(send_data.encode("utf-8"))
# 接收服务器端发来的信息
recv_data = tcp_client_socket.recv(1024)
print("接收到的数据为:", recv_data.decode("gbk"))
# 关闭套接字
tcp_client_socket.close()
当应用程序希望通过TCP与另一个应用程序通信时,他会发送一个通信请求。这个请求必须送到一个确切的地址。在双方“握手”之后,TCP将在两个应用程序之间建立一个全双工(full-duplex)的通信。这个全双工的通信将占用两个计算机之间的通信线路,直到他被一方或双方关闭为止。
标志位,TCP的6个标志位
所谓标志位,一种二进制的指令。
TCP是因特网的传输层协议,使用三次握手协议简历连接。当主办方发出SYN连接请求后,等待对方的回答SYN+ACK,并最终对对方的SYN执行ACK确认。这种建立连接的方法可以防止产生错误的连接。
TCP三次握手的过程:
三次握手完成,TCP客户端和服务器端成功建立连接,可以开始传输数据。
[外链图片转存失败(img-k9jgdHC6-1565087614665)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1565060771148.png)]
建立一个连接需要三次握手,而终止一个连接要经过四次挥手,这个是由TCP的半关闭状态(Half-close)造成的。
注意:
FIN的接收也作为一个文件结束符(end-of-file)传递给接收端应用进程,放在已排队等候该应用进程接收的任何其他数据之后,因为,FIN的接收意味着接收端应用进程在相关连接上再无额外数据可接收。
3、一段时间后接收到这个文件结束符的应用进程将会调用close关闭它的套接字。这导致它的TCP也发送一个FIN。
4、接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN。(既然每端都需要一个FIN和一个ACK,因此,通常需要4个字节)
广播
Mac地址
arp协议
路由器
局域网
子网掩码