一、软件开发的架构:
1、C/S架构
C/S:Client(客户端)与Server(服务端),这种架构是从用户层面划分(物理层面划分)。
这里的客户端一般泛指客户端应用程序EXE,程序需要先安装后才能在用户的电脑上运行,对用户的电脑操作系统依赖较大。
2、B/S架构
B/S:Browser(浏览器端)与Server(服务端)架构。这种架构是从用户层面来划分的。
Browser浏览器,其实是一种Client客户端,只是这个客户端不需要大家安装什么应用程序,只需要在浏览器上通过HTTP请求服务器相关资源(网页资源),客户端Browser浏览器就能进行增删改查。
二、网络基础(计算机网络的基础概念)
1、网络到底是什么?计算机之间是如何通信的?
早期:连机
以太网:局域网与交换机
广域网与路由器
(1)、广播
主机之间”一对多“的通讯模式,网络对其中每一台主机发出的信号都进行无条件复制并转发,所有的主机都可以收到所有的信心,由于主机其不用选择路径,多有网络成本很低廉,有线电视网就是典型的广播型网络。在数据网络总也允许广播的存在,但其被限制在二层交换即得局域网范围内,禁止广播数据穿过路由器,防止广播数据影响大面积的主机。
(2)、IP地址与IP协议
规定网络地址的协议叫IP协议,它的定义称之为IP地址,广泛采用的v4版本即ipv4,它规定了网络地址是由32位2进制表示
范围:0.0.0.0~255.255.255.255
一个ip地址通常写成四段十进制数,例:10.16..15.18
(3)、mac地址
head中包含的源和目标由来,ethernet规定接入Internet的设备都必须是具备网卡,发送端和接收端的地址是指网卡的地址,即mac地址。
mac地址:每块网卡出厂时都被印上了一个世界上唯一的mac地址,长度时48位2进制,通常由21位16进制数表示(前六位是厂商编号,后六位是流水线号)
(4)、arp协议——查询IP地址和mac地址的对应关系
arp协议:地址解析协议(ARP:Address Resolution Protocol)。是根据IP地址获取物理地址的一个TCP/IP协议
主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址。
收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。
地址解析协议时建立在网络中的各个主机互相信任的基础上的,网络上的主机可以自主发送ARP应答消息,其他主机收到应答报文时不会检测该报文的真实性就会将其计入本机ARP缓存。由此攻击者就可以向某一主机发送伪ARP应答报文,使其发送的信息无法到达预期的主机或到达错误的主机,这就构成 了一个ARP欺骗。ARP命令可用于查询本机ARP缓存中IP地址和MAC地址的对应关系、添加或删除静态对应关系等。相关协议由RARP、代理ARP。NDP用在IPv6中代替地址解析协议。
(5)、路由器
路由器(Router),是连接因特网中各局域网、广域网的设备,他不会根据通道的情况自动选择和设定路由,以最佳路径,按照前后顺序发送信号。路由器只是互联网络的枢纽。目前路由器广泛应用于各行各业,各种不同档次的产品已经成为实现各种骨干网内部连接、骨干网间互联和骨干网与互联网互联互通业务的主力军。路由器和交换机之间主要区别就是交换机发生在OSI参考模型第二层(数据链路层),而路由器发生在第三层,即网络层。这一区别就决定了路由器和交换机在移动信息的过程中需使用不同的控制信息,两者实现各自功能的方式是不同的。
路由器又称为网关设备(Gateway)是用于连接多个逻辑上分开的网络,所谓网络是代表一个单独的网络或者一个子网。当数据从一个子网传输到另一个子网时,可通过路由器的路由功能来完成。因此,路由器具有判断网络地址和选择IP路径的功能,,它能在多个网络互联环境中建立灵活的连接,可用完全不同的数据分组和介质访问方法连接各种子网,路由器只能接收源站或其他路由器的信息,属网络的一种互联设备。
(6)、局域网
局域网(Local Area Network,LAN)是指在某一区域内由对台计算机互联的计算机组。一般是方圆几千米以内。局域网可以实现文件管理、应用软件共享、打印机共享、工作组内的日程安排、电子邮件和传真等通信服务。局域网时封闭型的,可以由办公室内的两台计算机组成,也可以由一个公司内的上千台计算机组成。
(7)、子网掩码
子网掩码就是表示子网络中特征的一个参数。它在形式上等同于IP地址,也是一个32为二进制数。它的网络部分全部为1,主机部分全部为0。例如IP地址172.16.10.1,如果已知网络部分是前24位,主机部分是后8位,那么子网掩码是1111111.11111111.11111111.00000000,写成十进制就是255.255.255.0。
知道子网掩码就能判断任意两个IP地址是否处在同一个子网。判断方法是将两个IP地址与子网掩码进行AND运算(两个数位都为1,运算结果为1,则为2),然后比较结果是否相等,如果是真的话,就表明他们在同一个子网络中,否则就不是。
比如,已知IP地址172.16.10.1和172.16.10.2的子网掩码都是255.255.255.0,请问它们是否在同一个子网络?两者与子网掩码分别进行AND运算,172.16.10.1:10101100.00010000.00001010.000000001255.255.255.0:11111111.11111111.11111111.00000000AND运算得网络地址结果:10101100.00010000.00001010.000000001->172.16.10.0 172.16.10.2:10101100.00010000.00001010.000000010255.255.255.0:11111111.11111111.11111111.00000000AND运算得网络地址结果:10101100.00010000.00001010.000000001->172.16.10.0结果都是172.16.10.0,因此它们在同一个子网络。例如
@IP协议的作用主要有两个,一个是为每台计算机分配IP地址,另一个是确定哪些地址在同一个子网络。
2、tcp协议和udp协议
(1)、端口:
一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等。这些服务完全可以通过一个IP地址来实现。那么主机是怎样区分不同的网络服务的呢?显然不能只靠IP地址,因为IP地址与网络服务的关系是一对多的关系,实际上是通过“IP + 端口号”来区分不同的服务。
(2)TCP协议:
当应用程序希望通过TCP与另一个应用程序通信时,他会发送一个通信请求,这个请求必须被送到一个确切的地址,在双方“握手”之后,TCP将在两个应用程序之间建立一个全双工(full-duplex)的通信。
这个全双工的通信将占用两个计算机之间的通信线路,直到它被一方或双方关闭为止。
@TCP三次握手:
TCP是因特网中的传输层协议,使用三次握手协议建立连接。当主动方发出SYN连接请求后,等待对方回答SYN+ACK,并最终对对方的 SYN 执行 ACK 确认。 TCP三次握手的过程如下:(1)客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。(2)服务器端收到SYN报文,回应一个SYN (SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV状态。(3)客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态。三次握手完成,TCP客户端和服务器端成功地建立连接,可以开始传输数据了。
@TCP四次挥手
tcp四次挥手,由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7) 由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(3)、UDP协议:
当程序希望通过UDP与一个应用程序通信时,传输数据之前源端和终端不建立连接。
当它想传送时就简单地去抓取来自应用程序的数据,并尽可能的把它扔到网络上。
(4)、tcp和udp的对比
TCP:传输控制协议,提供的时面向连接、可靠的字节流服务。当客户和服务彼此交换数据前,必须先在双发之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据流,流量控制等。保证数据从一端到另一端。
UDP:用户数据报协议,是一个简单的面向数据报的运输协议。UDP不提供可靠性,它只能是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户之间建立一个连接,且没有超市重发机制,故而传输速度很快。
3、互联网协议与osi模型:
(1)、互联网协议按照功能不同分为osi七层或tcp/ip五层或tcp/ip四层
(2)、每层运行常见的物理设备及协议
应用层:计算机,服务器。(HTTP,FTP,TFTP,SMTP,SNMP,DNS)
传输层:防火墙(TCP,UDP) 网络层:路由器(IP,ICMP.IGMP) 数据链路层:交换机。(ARP,RARP) 物理层:网卡。(底层协议)
三、socket概念
1、socket层
2、理解socket
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
(其实站在我们开发的角度上看,socket就是一个模块。我们通过调用模块中已经实现的方法建立两个进程之间的连接和通信。
也有人将socket说成ip+port,因为ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序。所以我们只要确立了ip和port就能找到一个应用程序,并且使用socket模块来与之通信。)3、套接字(socket)的发展史
套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。
基于文件类型的套接字家族
套接字家族的名字:AF_UNIX
unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信
基于网络类型的套接字家族
套接字家族的名字:AF_INET
还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族 ,但由于我们只关心网络编程,所以大部分的时候只是用AF_INET。
4、tcp协议和udp协议
tcp(Transmission Control Protocol)可靠的、面向连接的协议(例如打电话)、传输效率低、全双工通信(发送缓存和接收缓存)、面向字节流。使用TCP的应用:Web浏览器、电子邮件、文件传输程序。
udp(User Datagram Protocol)不可靠、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统(DNS)、视频流、ip语音(VoIP)。
四、套接字(socket)初使用
1、基于TCP协议的socket。(tcp是基于连接的,必须先启动服务端,然后再启动客户端去连接服务器)
server端:
import socketsk = socket.socket() #创建socket对象sk.bind(('127.0.0.1',5208)) #把地址和端口绑定到套接字sk.listen() #监听连接conn,addr = sk.accept() #接收客户端连接ret = conn.recv(1024) #接收客户端信息print(ret) #打印客户端信息conn.send(b'hello') #向客户端发送信息conn.close() #关闭客户端套接字sk.close() #关闭服务器套接字 (可选)
client端
import socketsk = socket.socket() #创建客户端套接字sk.connect(('127.0.0.1',5208)) #尝试连接服务器sk.send(b's_hello')ret = sk.recv(1024) #对话(发送/接收)print(ret)sk.close() #关闭客户端套接字
2、基于UDP协议的socket(udp是无连接的,启动服务之后可以直接接收消息,不需要提前建立连接)
server端
import socketudp_sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #创建一个服务器的套接字 udp_sk.bind(('127.0.0.1',5208)) #绑定服务器套接字 msg,addr = udp_sk.recvfrom(1024) print(msg) udp_sk.sendto(b'c_hello',addr) #对话(接收/发送) udp_sk.close() #关闭服务器套接字
client端
import socketip_port = ('127.0.0.1',5208)udp_sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)udp_sk.sendto(b's_hello',ip_port)back_msg,addr = udp_sk.recvfrom(1024)print(back_msg.decode("utf-8"),addr)
@示例:
1、QQ聊天:
server端
import socketip_port = ('127.0.0.1',8080)udp_server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)udp_server.bind(ip_port)while 1: qq_msg,addr = udp_server.recvfrom(1024) print('来自%s:%s的一条消息:%s' %(addr[0],addr[1],qq_msg.decode('utf-8'))) back_msg = input("回复消息:").strip() udp_server.sendto(back_msg.encode('utf-8'),addr)
client端
import socketBUFSIZE = 1024udp_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)qq_name_dic = { '金老板':('127.0.0.1',8080), '哪吒':('127.0.0.1',8080), 'egg':('127.0.0.1',8080), 'yuna':('127.0.0.1',8080),}while 1: qq_name = input("请选择聊天对象:").strip() while 1: msg = input("请输入消息,回车键发送,输入q结束和他聊天:").strip() if msg == "q": break if not msg or not qq_name or qq_name not in qq_name_dic: continue udp_client.sendto(msg.encode('utf-8'),qq_name_dic[qq_name]) back_msg,addr = udp_client.recvfrom(BUFSIZE) print('来自%s:%s的一条消息:%s' %(addr[0],addr[1],back_msg.decode('utf-8'))) udp_client.close()
2、时间服务器
server端
from socket import *from time import strftimeip_port = ('127.0.0.1',8080)bufsize = 1024tcp_server = socket(AF_INET,SOCK_DGRAM)tcp_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)tcp_server.bind(ip_port)while 1: msg,addr = tcp_server.recvfrom(bufsize) print('======>',msg) if not msg: time_fmt = 'Y%-%m-%d %X' else: time_fmt = msg.decode('utf-8') back_msg = strftime(time_fmt) tcp_server.sendto(back_msg.encode('utf-8'),addr)tcp_server.close()
client端
from socket import *ip_port = ('127.0.0.1',8080)bufsize = 1024tcp_client = socket(AF_INET,SOCK_DGRAM)while 1: msg = input("请输入时间格式(%Y-%m-%d):").strip() tcp_client.sendto(msg.encode('utf-8'),ip_port) data = tcp_client.recv(bufsize)
五、socket参数的详解
socket.socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)
创建socket对象的参数说明:
family | 地址系列应为AF_INET(默认值),AF_INET6,AF_UNIX,AF_CAN或者AF_RDS。(AF_UNIX域实际上是使用本地socket文件来通信) |
type | 套接字类型应为SOCK_STREAM(默认值),SOCK_DGRAM,SOCK_RAW或者其他SOCK_常量之一。 SOCK_STREAM是基于TCP的,有保障的(既能保证数据正确传送到对方)面向连接的SOCKET,多用于资料传送。 SOCK_DGRAM是基于UDP的,无保障的面向消息的socket,多用于在网络上发广播信息。 |
proto | 协议号通常为零,可以省略,或者在地址族为AF_CAN的情况下,协议应该为CAN_RAW或者CAN_BCM之一。 |
fileno | 如果指定了fileno,则其他参数讲被忽略,导致带有指定文件描述的套接字返回。 与socket.fromfd()不同,fileno将返回相同的套接字,而不是重复的。 这可能有助于使用socket.close()关闭一个独立的插座 |
六、在重启服务端是可能会遇到的报错
解决方法:
#加一条socket配置,重用ip和端口import socketfrom socket import SOL_SOCKET,SO_REUSEADDRsk = socket.socket()sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加sk.bind(('127.0.0.1',8080)) #把地址绑定到套接字sk.listen() #监听连接conn,addr = sk.accept() #接受客户端连接ret = conn.recv(1024) #接收客户端信息print(ret) #打印客户端信息conn.send(b'c_hello') #向客户端发送信息conn.close() #关闭客户端套接字sk.close() #关闭服务器套接字(可选)
@借鉴地址:https://www.cnblogs.com/clschao/articles/9593164.html