网络编程
网络编程
1.信息传递
两个运行总的程序如何传递信息
答:通过文件
2.两台机器上的连个运行中的程序如何通信?
答:通过网络
2..网络应用开发构架
1.框架的初解 C\S 与B\S
C\S :C表示client 客户端 S表示 sever 客户端
属于C\S的基本应用场景:输入法 百度云 pycharm git VNC 红蜘蛛
B/S :B表示browser 浏览器 S表示 sever 客户端
属于B\S的基本应用场景:淘宝 邮箱 百度 博客园 知乎 豆瓣 抽屉
小结:B/S和C/S架构的关系:B/S可以说是特殊的C/S架构
2.通信
通信软件与硬件解析:
网卡 :是一个实际存在在计算机中的硬件
mac地址:每一块网卡上都有一个全球唯一的mac地址
交换机:是连接多态机器并帮助通讯的物理设备,只认识mac地址
协议:两台物理设备之间对于要发送的内容,长度,顺序的一些约定
ip地址:
1.ipv4协议 位的点分十进制 32位2进制表示——————————>0.0.0.0 - 255.255.255.255
2.ipv6协议 6位的冒分十六进制 128位2进制表示————————>0:0:0:0:0:0-FFFF:FFFF:FFFF:FFFF:FFFF:FFFF
公网ip :每一个ip地址要想被所有人访问到,那么这个ip地址必须是自己申请的
内网ip:192.172.0.0 - 192.172.255.255
172.16.0.0 - 172.31.255.255
10.0.0.0 - 10.255.255.255
arp协议:通过ip地址获取一台机器的mac地址
子网掩码:判断两台机器是否在同一个网段内的
port端口:ip 地址能够确认一台机器
范围: 0-65535
ip + port 确认一台机器上的一个应用
3. osi 七层模型
osi七层协议 | 协议 | 设备 |
应用层 | HTTP FTP TFTP SMTP SNMP DNS TELNET HTTPS POP3 DHCP | 网络服务与最终用户的一个接口。 |
表示层 | JPEG、ASCll、DECOIC、加密格式等 | 数据的表示、安全、压缩。(在五层模型里面已经合并到了应用层) |
会话层 | 对应主机进程,指本地主机与远程主机正在进行的会话 | 建立、管理、终止会话。(在五层模型里面已经合并到了应用层) |
传输层 | TCP UDP | 四层交换机、四层路由器 |
网络层 | ICMP IGMP IP(IPV4 IPV6) ARP RARP | 路由器、三层交换机 |
数据链路层 | MAC地址 | 网卡、交换机 |
物理层 | TCP/IP 层级模型结构 | 建立、维护、断开物理连接。(由底层网络定义协议 |
3.socket (套接字)
python socket模块 完成socket的功能
工作在应用层和传输层之间的抽象层
帮助我们完成了所有信息的组织和拼接
sokcet是网络操作的底层了
socket历史:
同一台机器上的两个服务之间的通信的
基于文件:
基于网路的多台机器之间的多个服务通信
4.tcp协议 与udp 协议
tcp协议和udp协议的特点:
tcp
答:一个面向连接的,流式的,可靠的,慢的,全双工通信
应用场景:邮件 文件 http web
udp
答:一个面向数据报的,无连接的,不可靠,快的,能完成一对一、一对多、多对一、多对多的高效通讯协议
应用场景 : 即时聊天工具 视频的在线观看
tcp协议:
建立连接的时候 : 三次握手
断开连接的时候 : 四次挥手
tcp 基本代码格式:
服务端端
import socket sk = socket.socket() sk.bind(('127.0.0.1',8898)) #把地址绑定到套接字 sk.listen() #监听链接 conn,addr = sk.accept() #接受客户端链接 ret = conn.recv(1024) #接收客户端信息 print(ret) #打印客户端信息 conn.send(b'hi') #向客户端发送信息 conn.close() #关闭客户端套接字 sk.close() #关闭服务器套接字(可选)
客户端
import socket sk = socket.socket() # 创建客户套接字 sk.connect(('127.0.0.1',8898)) # 尝试连接服务器 sk.send(b'hello!') ret = sk.recv(1024) # 对话(发送/接收) print(ret) sk.close() # 关闭客户套接字
udp代码:
sever端
import socket udp_sk = socket.socket(type=socket.SOCK_DGRAM) #创建一个服务器的套接字 udp_sk.bind(('127.0.0.1',9000)) #绑定服务器套接字 msg,addr = udp_sk.recvfrom(1024) print(msg) udp_sk.sendto(b'hi',addr) # 对话(接收与发送) udp_sk.close() # 关闭服务器套接字
client 端
import socket ip_port=('127.0.0.1',9000) udp_sk=socket.socket(type=socket.SOCK_DGRAM) udp_sk.sendto(b'hello',ip_port) back_msg,addr=udp_sk.recvfrom(1024) print(back_msg.decode('utf-8'),addr)
5.粘包
1.概念
同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种显现就是黏包.
tcp协议的粘包现象 :
2. 什么是粘包现象?
发生在发送端的粘包
1.由于两个数据的发送时间间隔短+数据的长度小
2. 所以由tcp协议的优化机制将两条信息作为一条信息发送出去了
3.为了减少tcp协议中的“确认收到”的网络延迟时间
3.发生在接收端的粘包 :
1.由于tcp协议中所传输的数据无边界,所以来不及接收的多条
2.数据会在接收放的内核的缓存端黏在一起
本质: 接收信息的边界不清晰
4.. 解决粘包问题
自定义协议1 首先发送报头 报头长度4个字节 内容是 即将发送的报文的字节长度 struct模块 pack 能够把所有的数字都固定的转换成4字节 再发送报文 自定义协议2 我们专门用来做文件发送的协议 先发送报头字典的字节长度 再发送字典(字典中包含文件的名字、大小。。。) 再发送文件的内容
5.简单的解决粘包代码
server端
import os
import socket
sk =sk.socket.socket()
sk.bind(("127.0.0.1",9000))
sk.listen()
conn,addr = sk.accept()
num = conn.recv(4)###接收4字节
num = struct.unpack('i',num)[0]###通过接收的4个字节得到文件名长度
file_name = conn.recv(num).decode('utf-8')###知道了文件名
file_size = conn.recv(4)###再接收4字节
filesize = struct.unpack('i',file_size)[0]###得到了文件内容大小
with open(file_name,'wb') as f:###根据文件名打开文件
conntent = conn.recv(filesize)###按照文件内容的大小接收文件的内容
f.write(content)###按照手上来的文件内容写文件
conn.close()
sk.close()
client 端
import os
import socket
import struct
sk = socket.socket()
sk.connect(('127.0.0.1',9001))
filename = input('请输入文件路径:')###输入文件名
filename = os.path.basename(filepath)###从文件路径中获取文件名
name_len = struck.pack('i',len(filename))###把长度变成4字节
sk.send(name_len)###发送文件名长度
sk.send(filename.encode('utf-8'))###发送文件名
filesize = os.path.getsize(filepath)###算出文件大小
file_len = struct.pack('i',filesize)###把文件大小变成4字节
sk.send(file_len)###发送文件大小
with open(filepath,'rb') as f:
content = f.read()###读出文件内容
sk.send(content)###发送文件内容
sk.close()
5.socketsever模块
server端 import socketsever class Myserver(socketserver.BaseRequestHandler): def handle(self): msg =self.request.recv(1024).decode("utf-8") self.request.send("1".encode("utf-8")) msg =self.request.recv(1024).decode("utf-8") self.request.send("1".encode("utf-8")) msg =self.request.recv(1024).decode("utf-8") self.request.send("1".encode("utf-8")) server = socketserver.ThreadingTCPserver(("127.0.0.1"),Myserver) server.serve_forever()
client端 import socket import time sk = socket.socket() sk.connect(("127.0.0.1",9000)) for i in range(3): sk.send(b"hello,yuan") msg =sk.recv(1024) print(msg) time.sleep(1) sk.close()
6.非阻塞IO模型
server端 import socket sk = socket.socket() sk.bind(("127.0.0.1,9000")) sk.setblocking(False) sk.listen() conn_1=[] del_1 =[] while True: try: conn,addr =sk.accept() print(conn) conn_1.append(conn) except BlockingIOError: for c in conn_1: try: msg =c.recv(1024).decode("utf-8") if not msg: del_1.append(c) continue print("-->",[msg]) c.send(msg.upper().encode("utf-8")) except BlockingIOError:pass for c in del_1: conn_1.remove(c) del_1.clear() sk.close()
client端 import time import socket sk = socket.spcket() sk.connect(("127.0.0.1",9000)) for i in range(30): sk.send(b"wusirt") msg =sk.recv(1024) print(msg) time.sleep(0.2) sk.close()
7.验证客户端的合法性
server端 import os import hashlib import socket def get_md5(secret_key,randseq): md5 =hashlib.md5(secret_key) md5.update(randseq) res =md5.hexdigest() return res def chat(conn): while True: msg =conn.recv(1024).decode("utf-8") print(msg) conn.send(msg.upper().encode("utf-8")) sk = socket.socket() sk.bind(("127.0.0.1",9000)) sk.listen() secret_key =b"zalexb" while True: conn,addr =sk.accept() randseq =os.urandom(32) conn.send(randseq) md5code =get_md5(secret_key,randseq) ret = conn.recv(32).decode("utf-8") print(ret) if ret == md5code: print("是合法的客户端") chat(conn) else: print("不是合法的客户端") conn.close() sk.clsoe()
client端 import hashilib import socket import time def get_md5(secret_key,randseq): md5 =hashlib.md5(secret_key) md5.update(randseq) res =md5.hexdigest() return res def chat(sk): while True: sk.send(b'hello') msg = sk.recv(1024).decode('utf-8') print(msg) time.sleep(0.5) sk = socket.socket() sk.connect(('127.0.0.1',9000)) secret_key = b'alexsb' randseq = sk.recv(32) md5code = get_md5(secret_key,randseq) sk.send(md5code.encode('utf-8')) chat(sk) sk.close()