C/S和B/S架构python
C : client S : server 客户端,服务端shell
B : browser S : server 浏览器,服务端编程
B/S架构本质也是C/S浏览器
网络的七层协议:(应表会传网数物)服务器
物理层:电信号(0和1)网络
数据链路层:把物理层的电信号分组,每一组叫一个数据报或数据帧,每一帧有:报头head和数据data两部分。多线程
头固定18字节:6:发送者地址/6:接收者地址/6:数据类型架构
网络层:ssh
ip:ipv4:32位2进制表示:点分十进制表示异步
子网掩码:经过子网掩码和ip判断两个ip是否处于同一个网段,经过ip地址和子网掩码作按位与运算
ip地址: 172.16.10.1: 10101100.00010000.00001010.000000001
子网掩码:255.255.255.0: 11111111.11111111.11111111.000000000
按位与运算:172.16.10.0 10101100.00010000.00001010.000000000
ip和mac有转换关系:主要是由于ARP协议和mac地址学习。
传输层:
tcp协议:
udp协议:
直接发送,不须要响应,因此数据不可靠。(看视频花屏)
端口:
会话层:使应用创建和维持会话,并能使会话得到同步。
表示层:做用之一是为异种机通讯提供一种公共语言,以便能进行互操做。
应用层:应用层向应用程序提供服务,这些服务按其向应用程序提供的特性分红组,并称为服务元素。
模块 | 描述 |
---|---|
socket | 基于传输层TCP、UDP协议进行网络编程的模块 |
asyncore | socket模块的异步版,支持基于传输层协议的异步通讯 |
asynchat | asyncore的加强版 |
cgi | 基本的CGI(Common Gateway Interface,早期开发动态网站的技术)支持 |
E-mail 和 MIME消息处理模块 | |
ftplib | 支持FTP协议的客户端模块 |
httplib、http.client | 支持HTTP协议以及HTTP客户端模块 |
imaplib | 支持IMAP4协议的客户端模块 |
mailbox | 操做不一样格式邮箱的模块 |
mailcap | 支持Mailcap文件处理的模块 |
nntplib | 支持NTTP协议的客户端模块 |
smtplib | 支持SMTP协议(发送邮件)的客户端模块 |
poplib | 支持POP3协议的客户端模块 |
telnetlib | 支持TELNET协议的客户端模块 |
urllib | 支持URL处理的模块 |
xmlrpc | 支持XML-RPC协议的服务器和客户端模块 |
接下来咱们会主要讨论socket模块
程序再使用socket以前,必须先建立socket对象,能够经过如下语法建立socket实例:
s = socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
那么创好socket对象后就须要区分服务端和客户端了。
做为服务器端使用的socket必须绑定到指定IP地址和端口,并在该IP地址和端口进行监听,接收来自客户端的链接。
socket对象提供了以下经常使用方法:
服务端:
import socket host = socket.gethostname() # 获取本机host server = socket.socket() server.bind((host,8080)) server.listen(5) while 1: c, addr = server.accept() # 与客户端创建链接 c.send(b"start:") while 1: '''通讯循环,try为了等待客户端断开后链接其余的客户端''' try: print(f"\t\033[1;36m{c.recv(1024).decode()}\033[0m") msg = input(">>").encode('utf-8') c.send(msg) except Exception: print("客户端断开链接了!") break
客户端:
import socket host = socket.gethostname() # 获取本机host cilent = socket.socket() cilent.connect((host, 8080)) while 1: '''通信循环''' print(f"\t\033[1;36m{cilent.recv(1024).decode()}\033[0m") msg = input(">>").encode('utf-8') cilent.send(msg)
TCP协议中的数据都是以数据流(type=SOCK_STREAM)的形式传递的,很容易发生几回send的数据被一次recv(接收),或者被截成了好几段。为了解决粘包问题,咱们借用了数据报的思想,给每一条数据加一个固定长度的头。这里引入struct
模块来建立固定的头。
示例:写一个仿SHH的客户端和服务端
服务端
import socket import subprocess import struct server = socket.socket() host = socket.gethostname() port = 8081 server.bind((host, port)) server.listen(5) while 1: c, addr = server.accept() print(addr, "链接了 >>>") msg = b"hello " le = struct.pack('i',len(msg)) # 将要发送的数据的长度封装成固定长度为4的二进制数据 c.send(le) # 先发送一个头 c.send(msg) # 再发送数据 try: while 1: ssh = c.recv(1024) obj = subprocess.Popen(ssh.decode('gbk'), shell=True, stdout=subprocess.PIPE , stderr=subprocess.PIPE) # subprocess是与系统交互的模块 msg = obj.stdout.read() or obj.stderr.read() # 必然拿到其中一项 le = struct.pack('i',len(msg)) # 将结果打上头 c.send(le) # 与上同样 c.send(msg) except Exception: print(" 断开链接 !")
客户端
import socket import struct client = socket.socket() host = socket.gethostname() port = 8081 client.connect((host,port)) while 1: le = struct.unpack('i', client.recv(4))[0] # 解析头,获取数据长度 print(client.recv(le).decode('gbk')) # shell只接收gbk编码 ssh = input(" 请输入命令 >>") client.send(ssh.encode('gbk')) # 返回执行结果
socketserver模块实现了多线程通讯。使用socketserver建立服务端:
#使用socketserver写服务端 import socketserver #本身定义一个类,必须继承StreamRequestHandler或BaseRequestHandler class MyTcp(socketserver.StreamRequestHandler): #必须重写handle方法 def handle(self): '''这是服务端与客户端交互的方法''' try: while True : #通讯循环 # print(self) #给客户端回消息 #conn对象就是request #接收数据 print(self.client_address) data=self.request.recv(1024) print(data) if len(data)==0: return #发送数据 self.request.send(data.upper()) except Exception: pass if __name__ == '__main__': #实例化获得一个tcp链接的对象,Threading意思是说,只要来了请求,它自动的开线程来处理链接跟交互数据 #第一个参数是绑定的地址,第二个参数传一个类 server=socketserver.ThreadingTCPServer(('127.0.0.1',8009),MyTcp) #一直在监听 #这么理解:只要来一个请求,就起一个线程交互 server.serve_forever()