用到的工具下载链接
目前常见的都是 ipv4
当然也有ipv6
IP地址根据网络号和主机号来分,分为A、B、C三类及特殊地址D、E。 全0和全1的都保留不用。
A类:(1.0.0.0-126.0.0.0)(默认子网掩码:255.0.0.0或 0xFF000000)第一个字节为网络号,后三个字节为主机号。该类IP地址的最前面为“0”,所以地址的网络号取值于1~126之间。一般用于大型网络。
B类:(128.0.0.0-191.255.0.0)(默认子网掩码:255.255.0.0或0xFFFF0000)前两个字节为网络号,后两个字节为主机号。该类IP地址的最前面为“10”,所以地址的网络号取值于128~191之间。一般用于中等规模网络。
C类:(192.0.0.0-223.255.255.0)(子网掩码:255.255.255.0或 0xFFFFFF00)前三个字节为网络号,最后一个字节为主机号。该类IP地址的最前面为“110”,所以地址的网络号取值于192~223之间。一般用于小型网络。
D类:是多播地址。该类IP地址的最前面为“1110”,所以地址的网络号取值于224~239之间。一般用于多路广播用户[1] 。
E类:是保留地址。该类IP地址的最前面为“1111”,所以地址的网络号取值于240~255之间。
在IP地址3种主要类型里,各保留了3个区域作为私有地址,其地址范围如下: A类地址:10.0.0.0~10.255.255.255 B类地址:172.16.0.0~172.31.255.255 C类地址:192.168.0.0~192.168.255.255
回送地址:127.0.0.1。 也是本机地址,等效于localhost或本机IP。一般用于测试使用。例如:ping 127.0.0.1来测试本机TCP/IP是否正常。
这个地址是不是特殊地址 还是要看 注册表
比如我们的家庭宽带 被 nat 转发 看起来是公网ip , 但其实 是一个 局域网ip 当然 他肯定是 A 类地址 100 (10进制)打头的 其实有一些是 共享地址空间
具体指可以看这个链接。
ipv4 专用地址注册表
局域网是指 几台机器ip地址 网络号一样的但是 他们的 主机号不一样 192.168.0.0 最后一位 是 主机号, 0 代表没有 计算机, 255 用于广播,所以 0和 255 不用做 ip地址, 所以只有254个位置
大型企业计算机多的时候就可以使用 A 类 或者 B 类地址
所以推出了ipv6 ipv6 是一个128位(bit)的整数 换算成正常地址也有32个数字 分为 8段 特殊地址
127.0.0.1 本机地址 192.168.0.0 -192.168.255.255 位私有地址属于非注册地址,专门为组织机构内部使用
ip区分不同的计算机,要区分不同的程序,就需要 用端口 端口使用一个16位的二进制整数来表示
对应的十进制是0-65535 FFFF(hex) 16个1
0-1023 都是我们的保留端口 特殊指定的,比如 电话号码,110等,都是有特殊使用的
比喻 ip相当于(地址)门牌号,端口相当于 房间号
约定的意思
比如朋友与朋友之间的约定
计算机之间也需要约定,比如人沟通需要使用同一种语言,
除非双方同时懂对方的语言,共同语言
国际标准化组织iso,定义了网络通信协议的基本框架 OSI 模型 7层
TCP 属于传输层 IP 属于网络层 用的最多的是TCP/IP是一个协议族,也就是多个协议
具体科普可以看下方链接
百度百科- ISO模型
tcp/ip 的 4层 和 iso 是一样的
应用层(就是iso 的应用层 表示层 会话层 )传输层互联网络层网络接口层(就是 iso 模型的 物理+数据链路层)百度百科 科普链接 TCP-IP
是传输层的两种协议 基于socket的编程接口
tcp类似于拨号打电话,需要建立虚拟连接,发送的数据是可靠的,核心数据 使用TCP,速度比 udp 稍慢udp类似于发短信,不需要建立专门的虚拟连接,发送数据是不可靠的,传输数据是面向无连接的 非核心数据则使用 udppython 基于 socket 套接字进行通信
TCP的Socket名称是 SOCK_STREAM 创建套接字可以使用 socket.socket()
tcp代码如下
tcpSocket=socket.socket(AF_INET,SOCK_STREAM)创建无连接的UDP 名字是 SOCK_DGRAM
UDP 代码如下:
udpSocket=socket.socket(AF_INET,SOCK_DGRAM)用这个软件来 接收 8989 是我们 代码这里的地址。 而 8080 是 调试助手的地址。
通过操作码识别 是什么包
其实使用 http 模块也可以实现文件共享。
python -m http.server 8080 开启一个 web 服务 然后 用 ip地址访问就可以了
关于套接字socket编程的文档
python 中的传输 和 协议文档
http- 模块 - 文档
http.server —HTTP服务器 文档
http.client —HTTP协议客户端 文档
socket ——低层组网接口 文档
socketserver ——网络服务器框架 文档
struct 文档
格式字符具有以下含义;鉴于C和python值的类型,它们之间的转换应该是显而易见的。“标准大小”列是指使用标准大小时打包值的大小(以字节为单位);也就是说,当格式字符串以 '<' , '>' , '!' 或 '=' . 使用本机大小时,打包值的大小取决于平台。
单位都为 字节
格式
C类型
Python 类型
标准尺寸
笔记
x
填充字节 pad byte
无价值 no value
c
char
长度为1的字节 bytes of length 1
1
b
signed char
整数 integer
1
(1) ,(二)
B
unsigned char
整数
1
(2)
?
_Bool
布尔 bool
1
(1)
h
short
整数
2
(2)
H
unsigned short
整数
2
(2)
i
int
整数
4
(2)
I
unsigned int
整数
4
(2)
l
long
整数
4
(2)
L
unsigned long
整数
4
(2)
q
long long
整数
8
(2)
Q
unsigned long long
整数
8
(2)
n
ssize_t
整数
(3)
N
size_t
整数
(3)
e
(6)
浮动 代表 浮点数 float
2
(4)
f
float
浮动
4
(4)
d
double
浮动
8
(4)
s
char[]
bytes 类型
p
char[]
bytes 类型
P
void*
整数
(5)
类型
字节顺序
尺寸
对准
@
本地的
本地的
本地的
=
本地的
标准
没有人
<
小字节
标准
没有人
>
大字节
标准
没有人
!
网络(=big endian)
标准
没有人
文件名是 face.jpg 操作码文件名0模式0
所以发送 读写请求的格式为 1test.jpg0octet0 操作码 1 要求占位 两个 字节 上面的表格 中 H 表示整数两个字节 然后网络格式 ! test.jpg 长度为 8个字节 所以是 8个 s 可以缩写 8s %d 格式化字符串。 根据 len 函数 计算长度。然后 0 占位 1 个字节 用 b 为啥不用 s b代表整数类型。 然后 模式 octet 5个字节 所以 5s
然后得到如下
struct.pack('!H%dsb5sb'%len(filename),1,filename.encode(),0,'octet'.encode(),0)
import struct from socket import * filename='test.jpg' server_ip='127.0.0.1' # 格式 值 操作码 文件名转化为字节 0 模式 0 # b 代表一个字节 H代表两个字节, ds是一个占位符, 5s 是octet的长度格式 # 这就是我们封装的 读的请求 send_data=struct.pack('!H%dsb5sb'%len(filename),1,filename.encode(),0,'octet'.encode(),0) #创建udp_socket套接字 udp_socket=socket(AF_INET,SOCK_DGRAM) udp_socket.sendto(send_data,(server_ip,69))#读写端口默认是69 #本地创建一个文件 f=open(filename,'ab') #a追加模式 b二进制 while True: recv_data=udp_socket.recvfrom(1024) # print(recv_data) ('19\x1a&\'()*56789:CDEFGHI', ('127.0.0.1', 63568)) #获取操作码及数据块编号 # 使用struct 模块 转换格式 caozuoma,ack_num=struct.unpack('!HH',recv_data[0][:4]) #序列解包,操作码和 数据块编号 #判断操作码是否是5如果是5,则是错误信息 if caozuoma == 5: print('文件不存在') break #将接收到的数据写入到文件中 f.write(recv_data[0][4:]) if len(recv_data[0])<516: #表示读取完 break # 如果没有读取完 我们要发送确认包 # 发送确认包 ack_data=struct.pack('!HH',4,ack_num) rand_port=recv_data[1][1] # 从收到的数据 获取服务器发送数据的随机端口 udp_socket.sendto(ack_data,(server_ip,rand_port))
这里用到的多线程 知识 马上就会写了。
下一篇就是。
# 客户端之间聊天 from socket import * from threading import Thread # 把所有链接的客户端都添加到此列表 sockets=[] def main(): # 创建server_socket套接字对象 server_socket = socket(AF_INET, SOCK_STREAM) # 绑定端口 server_socket.bind(('127.0.0.1', 8989)) # 监听 server_socket.listen() # 接收客户端的请求 while True: # 接收客户端的连接 # 循环 接收 客户端连接 client_socket, client_info = server_socket.accept() # 将客户端连接 添加到sockets 列表中。 sockets.append(client_socket) # 开启线程处理当前客户端的请求 t = Thread(target=readMsg, args=(client_socket,)) t.start() def readMsg(client_socket): #读取客户端发送来的消息 while True: recv_data=client_socket.recv(1024) #如果接收到的消息中结尾是bye,则在线客户端列表移除该客户端 if recv_data.decode('utf-8').endswith('bye'): # 如果此客户端。发送来 bye 则 移除此客户端连接。 并关闭连接。 sockets.remove(client_socket) client_socket.close() break # 将消息发送给所有在线的客户端 # 变量所有在线客户端列表 if len(recv_data)>0: for socket in sockets: socket.send(recv_data) if __name__ == '__main__': main()