网络编程--python

网络编程

1、介绍

(一)、概述

网络编程也叫套接字编程, Socket编程, 就是用来实现 网络互联的 不同计算机上 运行的程序间 可以进行数据交互

(二)、三要素

  • IP地址: 设备(电脑, 手机, IPad, 耳机...)在网络中的唯一标识.

  • 端口号: 程序在设备上的唯一标识.

  • 协议: 通信(传输)规则

(三)、ip

概述

设备(电脑, 手机, IPad, 耳机...)在网络中的唯一标识

分类

  • 按照 代数 划分:

    IPv4: 4字节, 十进制来表示, 例如: 192.168.13.157

    IPv6: 8字节, 十六进制来表示, 理论上来讲, 可以让地球上的每一粒沙子都有自己的IP.

  • 按照 Ipv4 常用类别划分:

    城域网: 第1段是网络地址 + 后3段是主机地址, 例如: 10.0.0.0

    广域网: 前2段是网络地址 + 后2段是主机地址, 例如: 10.21.0.0

    局域网: 前3段是网络地址 + 后1段是主机地址, 例如: 192.168.13.*

命令

  • 查看本机的IP:
    ipconfig 适用于 windows系统
    ifconfig 适用于 linux系统, Mac系统
  • 测试网络连接是否通畅:
    ping 主机地址 或者 域名

(四)、端口号

复制代码
端口:   传输数据的通道, 每个程序都有.  类似于: 每个教室都有自己的门.
端口号: 程序在设备上的唯一标识.
范围:   0 ~ 65535, 其中0 ~ 1023已经被系统占用或者用作保留端口, 你自己在使用的时候, 尽量规避这个号段.

(五)、协议

协议有很多种,这里取最常见的TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)来举例介绍。

作用

通信双方都要遵守的通信规则

特点

  • TCP

    1. 面向有连接的.
    2. 采用 流的方式传输数据, 理论上无大小限制.
    3. 安全(可靠)协议.
    4. 效率相对较低.
    5. 区分客户端 和 服务器端.
  • UDP

    1. 面向无连接.
    2. 采用 数据包 的方式传输数据, 有大小限制(每个包不超过64KB).
    3. 不安全(不可靠)协议.
    4. 效率相对较高.
    5. 不区分客户端 和 服务器端, 叫: 发送端和接收端.

三次握手

复制代码
1. 客户端像服务器端发出请求, 申请建立连接.
2. 服务器端校验客户端数据合法后, 给出客户端回执信息, 可以建立连接.
3. 客户端重新向服务器端发出请求, 建立连接.

四次挥手

复制代码
因为TCP协议是双向的, 需要两个方向都断开, 即: A => B,   B => A

命令行

复制代码
查看本机端口号和协议:  netstat -ano   如果是Linux或者Mac, netstat -anp     all network Protocol(所有的网络端口)

(六)、socket通信

原理

通信两端都有自己的socket对象,数据在两个socket之间通过字节流(TCP)或者数据包(UDP)的方式传输。

服务器端

复制代码
1. 创建服务器端Socket对象.
2. 绑定(服务器端的)ip和端口号, 元组形式.
3. 设置监听数量.
4. 等待客户端申请建立连接, 如果有客户端申请建立连接, 校验数据合法后, 会返回1个: (负责和该客户端交互的socket对象, 客户端的信息) 元组
5. 给客户端发送数据.        字节形式.
6. 接收客户端发送的数据.     字节形式.
7. 释放资源.

客户端

复制代码
1. 创建客户端Socket对象.
2. 连接(服务器端的)ip和端口号, 元组形式.
3. 发送数据给服务器端.
4. 接受服务器端发送的数据.  回执信息.
5. 释放资源.

2、socket

(一)、创建socket对象

python 复制代码
# 创建对象.
# object: 对象的意思
# 参1: Address Family: 地址族, 指定IP地址的协议, IPV4, IPV6, UNIX...
# 参2: Socket Type: 指定套接字的类型, TCP, UDP, UNIX...
# 这里的: socket.AF_INET: 指的是IpV4,  socket.SOCK_STREAM: 指的是 字节流的方式.
socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

(二)、编解码

复制代码
编解码指的是  字符串 和 二进制数据之间相互转换.
编码: 字符串(我们能看懂的) ==> 二进制(计算机能看懂)
解码: 二进制(计算机能看懂) ==> 字符串(我们能看懂的)

(三)、收发一句话

客户端

python 复制代码
import socket

# 在main中测试.
if __name__ == '__main__':
    # 1. 创建客户端Socket对象, 指定: 地址族, 传输类型.
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 连接(服务器端)地址和端口.
    client_socket.connect(("127.0.0.1", 2121))
    # 3. 接受服务器端发送的数据并打印.
    # 分解版
    # recv_data_bys = client_socket.recv(1024)
    # recv_data = recv_data_bys.decode("utf-8")
    # 合并版
    recv_data = client_socket.recv(1024).decode("utf-8")
    print(f'客户端收到: {recv_data}')
    # 4. 给服务器端发送数据(回执信息).
    client_socket.send('有内鬼, 终止交易! Over'.encode("utf-8"))
    # 5. 关闭Socket对象.
    client_socket.close()

服务器端

python 复制代码
import socket

# 在main中编写.
if __name__ == '__main__':
    # 1. 创建服务器端Socket对象, 指定: 地址族, 传输类型.
    # 参1: IPV4,  参2: 字节流
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 绑定地址和端口.
    server_socket.bind(("127.0.0.1", 2121))
    # 3. 设置监听数量.    范围: 1 ~ 128
    server_socket.listen(5)
    # 4. 等待客户端连接, 如有连接, 则返回: (和客户端交互的Socket对象, 客户端地址)
    print('等待客户端连接中.....')
    accept_socket, client_info = server_socket.accept()
    # 5. 给客户端发送数据.
    # accept_socket.send('Welcome to study socket!'.encode('utf-8'))
    accept_socket.send(b'Welcome to study socket!')

    # 6. 接受客户端发送的数据并打印.
    recv_data_bys = accept_socket.recv(1024)        # receive: 接收,  一次读取1024个字节
    # 把字节转成字符串, 并打印.
    recv_data = recv_data_bys.decode('utf-8')
    print(f'服务器端收到 {client_info} 发送的信息: {recv_data}')

    # 7. 关闭Socket对象.
    accept_socket.close()       # 一般只关闭 和客户端交互的socket对象.
    # server_socket.close()     # 服务器端socket对象一般不关闭.

上面的服务器收到一句话后,就会自动断开,不是很合理,优化为可以一次接收多个人的消息(同一时刻只能连接一个人),不主动结束。

服务器端接收多客户端消息

python 复制代码
import socket

# 在main中编写.
if __name__ == '__main__':
    # 1. 创建服务器端Socket对象, 指定: 地址族, 传输类型.
    # 参1: IPV4,  参2: 字节流
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 绑定地址和端口.
    server_socket.bind(("127.0.0.1", 2121))
    # 3. 设置监听数量.    范围: 1 ~ 128
    server_socket.listen(5)

    while True:
        try:
            # 4. 等待客户端连接, 如有连接, 则返回: (和客户端交互的Socket对象, 客户端地址)
            accept_socket, client_info = server_socket.accept()
            # 5. 给客户端发送数据.
            # accept_socket.send('Welcome to study socket!'.encode('utf-8'))
            accept_socket.send(b'Welcome to study socket!')

            # 6. 接受客户端发送的数据并打印.
            recv_data_bys = accept_socket.recv(1024)        # receive: 接收,  一次读取1024个字节
            # 把字节转成字符串, 并打印.
            recv_data = recv_data_bys.decode('utf-8')
            print(f'服务器端收到 {client_info} 发送的信息: {recv_data}')

            # 7. 关闭Socket对象.
            accept_socket.close()       # 一般只关闭 和客户端交互的socket对象.
            # server_socket.close()     # 服务器端socket对象一般不关闭.
        except:
            pass

此时客户端发送一句就会自动结束,而服务器端会一直运行,直到手动停止。平时我们发送消息时,一般主动结束才会结束,因此可以对代码做以下调整。

(四)、长连接

客户端和服务器端成功连接后, 可以一直收发数据, 而不用频繁的创建和销毁Socket对象.可以选择合适的时机, 销毁Socket对象

需求

客户端不断地给服务器端发送数据, 服务器端收到后并打印. 直至客户端发送 "886", 结束程序

客户端

python 复制代码
import socket

if __name__ == '__main__':
    # 1. 创建客户端Socket对象.
    cli_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 连接服务器端. ip 和 端口号
    cli_socket.connect(("127.0.0.1", 6666))

    # 3. 发送数据到服务器端.
    while True:
        # 3.1 提示用户录入要发送的数据, 并接收.
        data = input('请录入要发送的数据: ')
        # 3.2 将其转成二进制形式, 发送给服务器端.
        cli_socket.send(data.encode("utf-8"))
        # 3.3 判断用户是否要退出.
        if data == "886":
            break

    # 4. 释放资源.
    cli_socket.close()

服务器端

python 复制代码
import socket

if __name__ == '__main__':
    # 1. 创建服务器端Socket对象.
    ser_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 绑定服务器端ip 和 端口号.
    ser_socket.bind(("127.0.0.1", 6666))
    # 3. 设置监听连接数.
    ser_socket.listen(5)
    # 4. 启动监听, 等待客户端建立连接.
    accept_socket, client_info = ser_socket.accept()

    # 5. 接收客户端发送的信息.
    while True:
        # 5.1 接收客户端发送的信息(二进制形式 => 字符串)
        recv_data = accept_socket.recv(1024).decode("utf-8")
        # 5.2 打印接收到的客户端的消息.
        print(f'服务器端收到: {recv_data}')
        # 5.3 判断客户端是否发送了"886", 如果是, 结束程序.
        if recv_data == "886":
            break

    # 6. 释放资源.
    accept_socket.close()

(五)、文件上传

客户端

python 复制代码
import socket

if __name__ == '__main__':
    # 1. 创建客户端Socket对象.
    cli_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 连接服务器端. ip 和 端口号
    cli_socket.connect(("127.0.0.1", 8888))
    # 3. 读取数据源文件的信息, 并发送数据到服务器端.
    # with open('d:/绕口令.txt', 'rb') as src_f:
    with open('d:/图片/a.jpg', 'rb') as src_f:
        # 扩展: 你也可以考虑先把文件名发给服务器端, 然后再上传文件.
        # cli_socket.send('绕口令.txt'.encode('utf-8'))
        # 3.1 分批次读取, 一次读取 1024个字节.
        while True:
            # 3.2 具体的从文件中读取数据的动作.
            data = src_f.read(1024)
            # 3.3 将读取到的数据写给 => 服务器端.
            cli_socket.send(data)
            # 3.4 判断是否读取完毕.
            if len(data) <= 0:
                break
    # 5. 释放资源.
    cli_socket.close()

服务器端

python 复制代码
import socket

if __name__ == '__main__':
    # 1. 创建服务器端Socket对象.
    ser_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 绑定服务器端ip 和 端口号.
    ser_socket.bind(("127.0.0.1", 8888))
    # 3. 设置监听连接数.
    ser_socket.listen(10)
    # 4. 启动监听, 等待客户端建立连接.
    accept_socket, client_info = ser_socket.accept()

    # 5. 接收客户端的回执信息.
    # 5.1 关联目的地文件, 用于把客户端的数据写到该文件中.
    with open('./data/文件.txt', 'wb') as dest_f:
        # 5.2 循环接收客户端写过来的文件数据.
        while True:
            # 5.3 具体的接收客户端数据的动作.
            recv_data = accept_socket.recv(1024)
            # 5.4 判断读取到的数据是否为空, 为空, 说明文件传输完毕.
            if len(recv_data) <= 0:
                break
            # 5.5 把读取到的数据写入到目的地文件中.
            dest_f.write(recv_data)

    # 7. 释放资源.
    accept_socket.close()

在现实使用过程中,多个客户端会往服务器端发送文件,因此我们需要改造一下服务器端代码。

服务器端持续监听

python 复制代码
import socket

if __name__ == '__main__':
    # 1. 创建服务器端Socket对象.
    ser_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 绑定服务器端ip 和 端口号.
    ser_socket.bind(("120.0.0.1", 8888))
    # 3. 设置监听连接数.
    ser_socket.listen(10)

    try:
        count = 0  # 计数变量.
        while True:
            count += 1  # 走到这里, 说明是1个新文件.
            # 拼接文件名
            file_name = './data/文件_' + str(count) + '.jpg'
            # 4. 启动监听, 等待客户端建立连接.
            accept_socket, client_info = ser_socket.accept()
            # 5. 接收客户端的回执信息.
            # 5.1 关联目的地文件, 用于把客户端的数据写到该文件中.
            with open(file_name, 'wb') as dest_f:
                # 5.2 循环接收客户端写过来的文件数据.
                while True:
                    # 5.3 具体的接收客户端数据的动作.
                    recv_data = accept_socket.recv(8192)
                    # 5.4 判断读取到的数据是否为空, 为空, 说明文件传输完毕.
                    if len(recv_data) <= 0:
                        break
                    # 5.5 把读取到的数据写入到目的地文件中.
                    dest_f.write(recv_data)
            # 走到这里, 说明文件传输完毕.
            print(f'服务器端收到 {client_info} 上传文件成功!')
            # 7. 释放资源.
            accept_socket.close()
    except:
        pass
相关推荐
那雨倾城26 分钟前
使用 OpenCV 将图像中标记特定颜色区域
人工智能·python·opencv·计算机视觉·视觉检测
网络空间小黑2 小时前
TCP/IP 知识体系
网络·网络协议·tcp/ip·计算机网络·5g·wireshark·信息与通信
belldeep3 小时前
如何阅读、学习 Tcc (Tiny C Compiler) 源代码?如何解析 Tcc 源代码?
c语言·开发语言
LuckyTHP3 小时前
java 使用zxing生成条形码(可自定义文字位置、边框样式)
java·开发语言·python
Dotrust东信创智3 小时前
面向SDV的在环测试深度解析——仿真中间件SIL KIT应用篇
网络·中间件·汽车
leoufung4 小时前
ECPF 简介
linux·网络·kernel
mahuifa4 小时前
(7)python开发经验
python·qt·pyside6·开发经验
学地理的小胖砸6 小时前
【Python 操作 MySQL 数据库】
数据库·python·mysql
安迪小宝6 小时前
6 任务路由与负载均衡
运维·python·celery
Blossom.1186 小时前
使用Python实现简单的人工智能聊天机器人
开发语言·人工智能·python·低代码·数据挖掘·机器人·云计算