IP地址

私有IP:本地局域网上的IP,专门为组织机构内部使用

  • 10.0.0.0~10.255.255.255

  • 172.16.0.0~172.31.255.255

  • 192.168.0.0~192.168.255.255

  • 公有IP:全球访问

IP地址127. 0. 0. 1~127. 255. 255. 255⽤于回路测试

⼦⽹掩码:区分网络号和主机号

端口号: 用来标记区分进程

网络基础-协议

根据TCP/IP协议簇功能的不同,将它分为了几种层次:

四层:

  • 网络接口层(链路层)

  • 网络层

  • 传输层

  • 应用层

七层:

  • 物理层

  • 数据链路层

  • 网络层

  • 传输层

  • 会话层

  • 表示层

  • 应用层

image-20210424151125242

Socket编程-简介

socket:通过网络完成进程间通信的方式。

image-20210424151206303

Socket本质是编程接口(API): Socket 是对 TCP/IP 协议的封装。

套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。

Socket编程-创建Socket

•创建Socket:

1
2
3
4
import socket
#导入套接字模块
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#s此时是一个socket对象,拥有发送和接收网络数据的功能

该函数带有两个参数(参数必须写)

  • AF_INET:ipv4协议⽤于 Internet 进程间通信

  • 套接字类型, 可以是 SOCK_STREAM(流式套接字, ⽤于
    TCP 协议) 或者 SOCK_DGRAM(数据报套接字, ⽤于 UDP 协
    议)

    • TCP慢但是稳定不会丢数据

    • UDP快但是可能会丢数据(黑客攻击)

  • 确定了IP地址端口号(ipv4协议),TCP或UDP协议之后,计算机之间可以进行通信

Socket编程

软件开发基本都需网络通信,应用程序接收发送信息。

使用操作系统提供的socket 编程接口来发送和接收信息,进行网络通信。

发送信息的应用程序,通过 socket 编程接口 把信息给操作系统的TCP/IP协议栈通讯模块;

通讯模块一层层传递给 其他通讯模块(网卡驱动等),最后再通过网卡等硬件设备发送到网络上去;

经过 网络上路由器的一次次转发,最终到了 目的程序 所在的 计算机(或者手机等设备) , 再通过 其 操作系统的 TCP/IP协议栈通讯模块 一层层上传。

最后接收信息的程序,通过 socket 编程接口 接收到了 传输的信息。

这个过程可以用下图来表示

socket 库

要进行socket编程,发送网络消息,我们可以使用 Python 内置的 socket 库 。

目前的socket编程,使用的最多的就是通过tcp协议进行网络通讯的。

tcp进行通讯的程序双方,分为服务端和客户端。

tcp 协议进行通讯的双方,是需要先建立一个虚拟连接的。然后双方程序才能发送业务数据信息。

建立tcp虚拟连接是通过著名的 三次握手 进行的。

我们现在来看一个 tcp协议进行通讯的 socket 服务端程序和客户端程序。

tcp 服务端程序 server.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#  === TCP 服务端程序 server.py ===

# 导入socket 库
from socket import *

# 主机地址为空字符串,表示绑定本机所有网络接口ip地址
# 等待客户端来连接
IP = ''
# 端口号
PORT = 50000
# 定义一次从socket缓冲区最多读入512个字节数据
BUFLEN = 512

# 实例化一个socket对象
# 参数 AF_INET 表示该socket网络层使用IP协议
# 参数 SOCK_STREAM 表示该socket传输层使用tcp协议
listenSocket = socket(AF_INET, SOCK_STREAM)

# socket绑定地址和端口
listenSocket.bind((IP, PORT))


# 使socket处于监听状态,等待客户端的连接请求
# 参数 8 表示 最多接受多少个等待连接的客户端
listenSocket.listen(8)
print(f'服务端启动成功,在{PORT}端口等待客户端连接...')

dataSocket, addr = listenSocket.accept()
print('接受一个客户端连接:', addr)

while True:
# 尝试读取对方发送的消息
# BUFLEN 指定从接收缓冲里最多读取多少字节
recved = dataSocket.recv(BUFLEN)

# 如果返回空bytes,表示对方关闭了连接
# 退出循环,结束消息收发
if not recved:
break

# 读取的字节数据是bytes类型,需要解码为字符串
info = recved.decode()
print(f'收到对方信息: {info}')

# 发送的数据类型必须是bytes,所以要编码
dataSocket.send(f'服务端接收到了信息 {info}'.encode())

# 服务端也调用close()关闭socket
dataSocket.close()
listenSocket.close()

tcp 客户端程序 client.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#  === TCP 客户端程序 client.py ===

from socket import *

IP = '127.0.0.1'
SERVER_PORT = 50000
BUFLEN = 1024

# 实例化一个socket对象,指明协议
dataSocket = socket(AF_INET, SOCK_STREAM)

# 连接服务端socket
dataSocket.connect((IP, SERVER_PORT))

while True:
# 从终端读入用户输入的字符串
toSend = input('>>> ')
if toSend =='exit':
break
# 发送消息,也要编码为 bytes
dataSocket.send(toSend.encode())

# 等待接收服务端的消息
recved = dataSocket.recv(BUFLEN)
# 如果返回空bytes,表示对方关闭了连接
if not recved:
break
# 打印读取的信息
print(recved.decode())

dataSocket.close()

UDP :User Data Protocol,用户数据报协议

TCP:Transmission Control Protocol,传输控制协议

TFTP

Trivial File Transfer Protocol,简单⽂件传输协议),使用这个协议,就可以实现简单文件的下载,tftp端⼝号为69。

实现TFTP下载器:

  • 下载:从服务器上将一个文件复制到本机上

  • 下载的过程:

    • 在本地创建一个空文件(与要下载的文件同名)
    • 向里面写数据(接收到一点就向空文件里写一点)
    • 关闭(接受完所有数据关闭文件)

image-20210424214121560

image-20210424214133777

当客户端接收到的数据⼩于516(2字节操作码+2个字节的序号+512字节数据) 时, 就意味着服务器发送完毕了 (如果恰好最后一次数据长度为516,会再发一个长度为0的数据包)。

struct模块使用

  • 构造下载请求数据:“1test.jpg0octet0”

  • import struct
    cmb_buf = struct.pack(“!H8sb5sb”,1,b“test.jpg”,0,b“octet”,0)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29


    如何保证操作码(1/2/3/4/5)占两个字节?如何保证0占一个字节?

    - !H8sb5sb: ! 表示按照网络传输数据要求的形式来组织数据(占位的格式)
    H 表示将后面的 1 替换成占两个字节
    8s 相当于8个s(ssssssss)占8个字节
    b 占一个字节

    struct模块可以按照指定格式将Python数据转换为字符串,该字符串为字节流

    struct模块中最重要的三个函数是pack(), unpack(), calcsize()

    按照给定的格式(fmt),把数据封装成字符串(实际上是类似于c结构体的字节流)

    - pack(fmt, v1, v2, ...)

    按照给定的格式(fmt)解析字节流string,返回解析出来的元组

    - unpack(fmt, string)

    计算给定的格式(fmt)占用多少字节的内存

    - calcsize(fmt)

    ```python
    struct.pack("!HH",4,p_num)
    #
    cmdTuple = struct.unpack("!HH", recvData[:4])

TCP

TCP:传输控制协议。

TCP通信模型: 在通信之前,必须先等待建立链接。

image-20210425214049971