网络编程
# 网络编程
2台机器之间的通信 -- 网卡 - mac地址 - 物理地址 多台机器之间的通信 -- 交换机 mac 世界唯一 ip地址 虚拟地址 随着时间/空间变化而变化 ipv4 4位点分十进制 0.0.0.0 - 255.255.255.255 ipv6 6位:分十六进制 0.0.0.0.0.0 - 255.255.255.255.255.255 127.0.0.1 本机回环地址 0.0.0.0 本机所有的ip 包括127.0.0.1/实际ip 交换机的工作方式: 单播/广播/组播 arp协议 通过ip找mac 交换机:广播 将要找的机器的信息发给局域网内的所有机器 交换机-->单播 返回要找机器的那台机器 公网 ip: 不管在哪都能找见的ip地址 内网 ip: 校园网,公司内网,员工网 保留字段: 专门给内网使用,公网ip永远不会占用内网ip的地址 192.168.0.1 - 192.168.255.255 172.168.0.1 - 172.168.255.255 10.0.0.1 - 10.255.255.255
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
局域网与局域网之间的机器通信 你要找的两台机器之间的网络是通的 机器a -->机器b 机器a -->交换机 -(网关ip)-> 路由器 -...-> 路由器 -(网关ip)-> 交换机 --> 机器b 我怎么知道机器a和机器b不是一个网段的? 子网掩码 机器a和子网掩码 进行一个按位与 网段信息 机器b和子网掩码 进行一个按位与 网段信息 两个网段信息一致说明是一个局域网的,不一致说明不在一个局域网
交换机工作机制: 只认识mac地址, 广播\单播\组播 路由器工作机制: 路由表,认识ip地址 网关ip? 子网掩码? 端口 0-65535 # 通过某一个端口定位到机器上的某一个应用 22 端口 操作系统ssh命令
传递信息的方式 TCP协议 打电话 : 可靠的\面向连接的\慢 Transmission Control Protocol
UDP协议 发短信 : 不可靠的\无连接的\快 User Datagram Protocol
计算机OSI协议 https://baike.baidu.com/item/%E4%B8%83%E5%B1%82%E6%A8%A1%E5%9E%8B/1441391#2_1 应用层 : socket :承包了下面四层复杂的数据包的封装 传输层 : tcp/udp 端口 四层路由器 四层交换机 网络层 : ip地址 三层路由器 三层交换机 数据链路层 : mac arp协议 二层交换机 网卡 物理层 数模转换 高低电平
只有 tcp 黏包问题:
1 从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点
2 实质上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的
什么时候要解决黏包? 连续send且不是在大文件传输过程中
发送大文件 不需要解决黏包问题
黏包问题解决办法:
server 要想发送具体的文件数据,先要将文件的大小\文件的名称都要发送给client端
struct解决黏包 借助struct模块,我们知道长度数字可以被转换成一个标准大小的4字节数字。因此可以利用这个特点来预先发送数据长度 发送时 - 先发送struct转换好的数据长度4字节 - 再发送数据 接收时 - 先接收4个字节使用struct转换成数字来获取要接收的数据长度 - 再按照长度接收数据
验证客户端连接的合法性 如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么利用hmac+加盐的方式来实现 HMAC (Hash-based Message Authentication Code) 更多参考https://www.cnblogs.com/Eva-J/articles/8244551.html#_label1
会发生黏包问题的两种情况:
1 发送方的缓存机制(发送端需要等缓冲区满才发送出去,造成黏包) 发送数据时间间隔很短,数据了很小,会合到一起,产生粘包
2 接收方的缓存机制(接收方不及时接受缓冲区的包) 造成多个包接收, (客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)
tcp协议的拆包机制
当发送端缓冲区的长度大于网卡的MTU时,tcp会将这次发送的数据拆成几个数据包发送出去。
MTU是Maximum Transmission Unit的缩写。意思是网络上传送的最大数据包。MTU的单位是字节。 大部分网络设备的MTU都是1500。如果本机的MTU比网关的MTU大,大的数据包就
会被拆开来传送,这样会产生很多数据包碎片,增加丢包率,降低网络速度。
两台机器之间通信 : 网络
网络开发的架构:
c/s client-server 例子就是各种独立软件 iqiyi youku letv tmall 等 一般说的是 .exe文件
b/s browser-server 所有的b/s也是c/s架构 浏览器解放了你的桌面图标,web编程都是b/s架构的
IP - Internet Protocol Address,又译为网际协议地址
"端口"是英文port的意译,可以认为是设备与外界通讯交流的出口。
windows上查看端口占用的情况 netstat -aon|findstr "49157"
ip地址精确到具体的一台电脑,而端口精确到具体的程序。
-- socket TCP 是基于连接的,必须先启动server,然后载启动客户端取链接server
理解socket 其实站在你的角度上看,socket就是一个模块。我们通过调用模块中已经实现的方法建立两个进程之间的连接和通信。 也有人将socket说成ip+port,因为ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序。 所以我们只要确立了ip和port就能找到一个应用程序,并且使用socket模块来与之通信。
- server端 - 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() #关闭服务器套接字(可选)
- client端 - import socket sk = socket.socket() # 创建客户套接字 sk.connect(('127.0.0.1',8898)) # 尝试连接服务器 sk.send(b'hello!') ret = sk.recv(1024) # 对话(发送/接收) print(ret) sk.close() # 关闭客户套接字
-- socket UDP 无连接的,启动服务之后可以直接接受消息,不需要提前建立连接
简单使用
- server - 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) #ip 端口 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)