25. Python语言 Web 开发 之 Socket 编程 · 第一章 UDP发送与接收数据

编程知识 更新时间:2023-04-25 07:58:00

UDP发送与接收数据

  • 本章主题
  • 关键词
  • 前导:
  • 计算机网络的发展及基础网络概念
    • 两台电脑的通信
  • IP地址介绍及分类
    • IP地址与IP协议
    • Windows 和 Linux 查看网卡信息
    • IP地址分类
    • 以太网 (局域网)
    • 广域网 (路由器)
    • 端口
  • 端口介绍
    • 端口分类
  • socket简介
    • TCP/IP协议
    • socket 介绍
  • UDP 发送与接收数据
    • udp发送数据
    • Udp接收数据
    • udp聊天器
  • 总结小便条

本章主题

  1. 计算机发展史,计算机网络的发展及基础网络概念;
  2. 实现模块与模块之间,不通过 引用 却又能实现 彼此能够灵活访问中间键
  3. IP地址介绍及分类;
  4. 什么是 端口端口 的作用是什么;
  5. 套接字函数 socket()
  6. UDP 发送与接收数据。

  

关键词

  1. 客户端:Client
  2. 浏览器:Browser
  3. 服务端:Server
  4. 目标端口:dest_port
  5. 目标IP:dest_ip
  6. 源IP:scr_ip
  7. 网络通信协议:TCP/IP(Transmission Control Protocol/Internet Protocol) 、UDP
  8. 套接字函数:socket()
  9. 创建套接字方法:socket(family = socket.AF_INET, type = socket.SOCK_DGRAM)
  10. 套接字发送方法:sendto()
  11. 数据:data
  12. 字节型:bytes
  13. 地址:address
  14. 关闭函数:close()

  

前导:

  现在有两个文件:
   文件 a.py

a = "hello world"
print(a)

   文件 b.py

print(a)

  现在如果我想 文件 b 访问到 文件 a 里的内容该怎么做?

  看到这,一定有读者朋友说:用模块啊 、用 “文件访问” 函数啊 ……

  可现在如果我们 不使用 上面这些方法,那我们如何能实现 文件 b 访问到 文件 a 里的内容?

  不通过导入模块的方式,如何实现在 a.py 中存数据,在 b.py 中读数据。

  其实,不同的模块之间存在着 隔离,以保证各自代码之间的 独立性

  而想要实现不同的模块之间的能够 灵活的访问,就要借助 中间键 从而实现不同的模块之间的够灵活的 彼此访问

  这是 同一计算机内 不同模块 之间的访问,如果 不同计算机 之间进行传输通信,那么就会使用到 网络。比如QQ,微信等APP。

  即然现在介绍模块之间的 中间键 时提到了 网络 和 各种软件,那我们顺带着也就简单的介绍一下 软件开发架构

  软件开发架构 分为 应用类程序Web类程序;那什么又是 应用类程序Web类程序呢?

  应用类程序:如 QQ、百度云盘 、网易云音乐 等等这类需要下载安装包,并需要对它们进行安装后才能进行使用的程序;

  Web类程序:如 网页版的百度、网页版的知乎、网页版的CSDN等等这类无需下载,直接通过网站地址就能够直接进行访问操作的程序。

  因为这些 程序类型 的不同,我们在进行程序开发的过程中也涉及到了各种不同的 开发架构;比如说:基于上面这两种不同的 程序类型 就有一种 C/S 开发架构。那什么是 C/S 开发架构呢?顾名思义,C:Client 客户端S:Server 服务端。那 客户端 是什么,服务端 又是什么呢?接下来我们也来简单的介绍一下:

  C:Client 客户端;用户使用的 入口 或者 端口 就是 客户端

  S:Server 服务端;一直运行,等待服务别人的 服务器 端口

  刚刚简单的给大家介绍完了 C/S 开发架构,接下来再给大家简单的介绍另外一种开发架构:B/S 开发架构。那什么是 B/S 开发架构呢?

  B:Browser 浏览器;接入网站地址的 入口 或者说是 端口

  S:Server 服务端;一直运行,等待服务别人的 服务器 端口

  典型的使用 B/S 开发架构的案例就是:网页版的百度、网页版的知乎、页游、网页传奇 这类无需下载 .exe 安装文件,但只要连接上网就能直接使用的 Web类程序

  使用 B/S 开发架构常用于 PC端 的开发;它的优势就是:统一入口。同样都是 程序,通过 B/S 开发架构的 程序 就无需再下载 .exe 安装文件,只需要明确 服务器端 的路径地址就可以直接通过 浏览器程序 直接的进行访问和使用。

  看完我对 C/S 开发架构 和 B/S 开发架构 的 简单介绍,我想此时一定会有读者朋友发问:B/S 开发架构 适用于 手机APP端 吗?

  我们现在对手机端程序的使用还是一种基于 C/S 开发架构 的使用模式:应用市场 => 搜索指定程序 => 下载 .exe 安装文件 => 安装 => 使用。那 移动手机端 现在有没有使用 B/S 开发架构的典型案例?即然出现了这个问题,那回复的答案一定是:有的。

  手机APP端使用 B/S 开发架构的典型案例就是:微信小程序。简单的介绍一下:微信 现在逐渐的转化为一个 浏览器,各种不同的 小程序 就是 图标化网站地址;当我们在使用每个不同的 小程序 的时候,就等于通过 微信 · 浏览器 直接访问各个不同的 网站地址。这不就是手机APP端使用 B/S 开发架构的典型案例。

  现在已经简单的介绍完了什么是 C/S 开发架构,什么是 B/S 开发架构,以及它们的各种不同的应用场景;接下来我们再一起来讨论讨论 C/SB/S 之间的关系。

  C/SB/S 之间有什么关系?虽然 B/SB 指的是 浏览器,但是这 浏览器 也是另外的一种 客户端。我们平时玩爬虫时,最常见的一句话是不是:模拟浏览器向服务器发送请求。 这里的 浏览器 也就是另外的一种 客户端

  通过前面这几句话的铺垫引生出下面这个结果:C/S 开发模式中包含于 B/S 开发模式,或者说 B/S 开发模式 是 C/S 开发模式中的一种模式。这个介绍可能有点绕,需要各位读者多读几遍,对这句话多多的细品细品。

  所以,我们之后讲的所有的网络编程都是 基于 C/S 开发架构衍生发展的。

  看到这,我想就会有读者朋友问了:我们之后的学习重心在 B/S 上,为什么我们现在又要学习 C/S 呢?

  因为使用 B/S 架构进行开发学习的时候还需要有前端的基础,因为它是基于Web页面上的,在我们之后讲解完 前端 或者 Django 框架Flask 框架,再回看 B/S 架构自然就 水到渠成 了。所以,我们之后所有的内容都是基于 C/S 架构 PC端进行讲解的。

  

计算机网络的发展及基础网络概念

  前面我们说过:网络 来源于 多台计算机 的应用而来。互联网 最早的应用来自于 二战 时的 信息传递,后来发现这玩意很方便,越用越好用;随着之后战争的结束,市场经济的繁荣,商场之间的战争与博弈,互联网技术 也随之逐渐的民用化、普及化。详细的计算机发展史,在此省略 两千万字,小编我就不在这浪费大家的阅读精力了,感兴趣的朋友可以自己去百度整合学习一下,顺带着把你的学习汇总和心得能够留在评论区,方便给更多的读者朋友进行普及和学习。

  

两台电脑的通信

  两台计算机通过 网线 链接两台计算机的 网孔 就可以以实现两台计算机 信息互联 的效果;网孔 的作用就是 网线 与计算机的 网卡 进行交互。

  当然 网线 的链接这是实现了两台计算机 物理 上的连接;如果多台计算机互联,传输信息时计算机该如何 甄别 谁是谁呢?这时,我们就需要通过每台计算机专属的 MAC编号 来对计算机进行识别了。

  此时,我们就来介绍一下什么是 MAC编号:每个 网卡 在完成制作后会有一个 唯一标识(全球唯一编号):MAC地址MAC地址(编号) 非常的长且复杂,是一串 48位的二进制编码;如果使用十六进制进行表示的话是一串 12位的十六进制编码。如果,每次进行信息传输前先访问这个 超长且不容易记忆MAC地址 是不是神TMD的繁琐;所以,如果在同一个网络里,在访问计算机前只要输入一个 编号 就能实现传输的话,是不是就方便很多了。这个编号,我们称它为 IP地址IP地址 就是一个编号,使用 IP地址 就能找到对应的 唯一标识 · MAC地址。这个操作,本质上是遵循 ARP协议 进行的一个联网操作。IPMAC 是有在 本质上的区别 的,它们不是一类东西,在这点认知上希望各位读者朋友要明确的理解一下。

  

IP地址介绍及分类

  前面我们已经简单又仔细的介绍了什么是 唯一标识(全球唯一编号):MAC地址,也提出了 IPMAC 是有在 本质上的区别 的。接下来,我们就来详细的了解与解释一下:到底什么是 IP

  

IP地址与IP协议

  规定 网络地址协议IP协议,它定义的 地址 称为 IP地址。现在广泛采用的V4版本的即 IPV4,它规定网络地址由 32位2进制 表示。

  查看本机IP方式:打开 “网络连接” => 双击链接的网络 => 点击 “详细信息…” 就可以查看到当前计算机的 各项联网信息

  第一步: 打开 “网络连接”,双击链接的网络。

  第二部: 点击 “详细信息…”

  看到当前计算机的 各项联网信息

  注意:
    • 一个 IPV4地址 通常写成 四段 十进制数,以 “.” 进行分隔;
    • IPV4地址值 的范围 0.0.0.0 - 255.255.255.255。

  

Windows 和 Linux 查看网卡信息

  通过 终端 调取IP信息的方法: 按 win键 + R ,在 “运行” 对话框里输入 “CMD”,点击 “确定” 或敲击 “回车键” 进入 “管理员控制台”,在 “管理员控制台” 里输入 “python” 验证 Python环境是否安装成功。

   Linux 操作系统 通过 终端 调取IP信息的方法:

ifconfig

   Linux 操作系统 开启/关闭 网卡的方法:

sudo ifconfig ens33 down		# 关闭 
sudo ifconfig ens33 up			# 开启

  注意:
    这只是虚拟机操作的扩展了解,后期会着重学习,在线这是课堂拓展。

   Windows 操作系统 通过 终端 调取IP信息的方法:

ipconfig

  

IP地址分类

  前面我们一直在讲的都是 IPV4,但是 IP协议 不是只有 IPV4 一种,接下来我们一起简单的来了解一下 IP地址的分类


  看到上面的图,我想一定会有朋友好奇了:为什么 IPV4 后跟的是 IPV6IPV5呢?难道也像iPhone一样跳过9,直接X了?其实并不是这样的,其实最初世界互联网组织在市场上是推出过 IPV5 的,只不过因为一些技术原因以及市场的问题导致 IPV5 推广并不太顺利,索性就直接放弃了。后来随着笔记本电脑以及移动端的普及,以及网路技术迅猛的发展,在2018年推广了 IPV6

  一个 IPV6地址 通常写成 六段 十进制数,以 “.” 进行分隔;IPV6地址值 的范围 0.0.0.0.0.0 - 255.255.255.255.255.255。

  在本快内容结束前,我们最后补充一个 特殊的IP地址:127.0.0.1

  这个 特殊的IP地址 叫做 本地回环地址 或者叫 locklhost;它的作用是:自己找自己。在框架创建的最初期,在IP地址的定义上通常默认定义就是这个 本地回环地址

  

以太网 (局域网)

  前面讲的内容都是 两台电脑 的链接,以及 信息的传输;接下来我们来看看 多台电脑 该如何链接。

  一根网线最多只能链接 两台电脑多台电脑 总不能需要 n-1根网线 吧。此时,我们就需要一个 辅助 连接 多台电脑 的设备:交换机

  交换机 为了解决 多台机器之间的通信 问题,通过 交换机 实现了 多台电脑以太网 (局域网)

  当然,以太网 (局域网) 的链接以及使用就需要一定的 机制 了。什么 机制 呢?那就是它的 广播机制。什么是 广播机制 呢?举个例子:我现在想通过 服务器1 把一条信息发给 服务器4。信息从 服务器1 发出到 交换机交换机 通过 服务器1 在发送信息前绑定的在信息里的 接收服务器4MAC码/IP地址 开始对 以太网 (局域网)所有服务器 开始 逐个甄别,直到找到对应的 MAC码/IP地址服务器4,然后将 交换机 里截留的 服务器1 发出的信息发送给 服务器4

  这整个机器的操作流程就是 以太网 (局域网)广播机制

  这 以太网 (局域网) 毕竟是一种 基础的联网,就是因为 基础 所以存在着各种的 不足缺陷。那什么样的 缺陷 衍化出了之后的 广域网 呢?这个 广播机制缺陷 就和它的名字一模一样,那就是 广播。我们再举个例子:

  案例主人公 王铁柱 因为 害羞,不好意思当众向案例女主角 张小花 表达爱意,于是 王铁柱 就想通过 以太网 (局域网) 向自己爱慕的小花 暗搓搓表白,但是因为 以太网 (局域网)广播机制王铁柱 这边刚把信息发出来,王铁柱的弟弟王二柱张小花的哥哥张大壮 虽然不知道 王铁柱张小花 发了什么信息,但是也 能看到 王铁柱给张小花 发信息,于是乎虽然不知道这一次 暗搓搓 表白 最后的结果怎么样,但是 王铁柱 夜半三更的一顿毒打 是跑不了了。

  还没知道自己的心爱的 女神 对自己的什么感觉就先挨了一顿 毒打,我们的大牛村一霸 王铁柱 同学那受过这种气啊,于是乎一怒之下就拆掉了自家的 服务器运营商 知道这件事后觉得 这哪成啊!王铁柱 同学可是我们的大客户啊,必须立刻马上 解决好我们 客户爸爸 的问题,安抚好我们 客户爸爸 受伤的心。而且,如果太多的 服务器 连接在 1台交换机 上,处理太多的信息会出现 网络风暴,于似乎就有了后面的 广域网

  

广域网 (路由器)

  前面说到了因为 以太网 (局域网)基础的联网,因为 基础 而存在的各种 不足缺陷 衍化出了之后的 广域网


  上面这幅图就是完整的 广域网 的搭建模型。

  我们前面说过一个 交换机 就是一个 局域网,如果想让 局域网局域网 之间联接,首先要通过彼此的 网关,然后通过 路由器 才能进行联接。

  网关的概念局域网 的机器想要访问 局域网 的机器,需要 通过网关 才能访问。

  此时如果想要知道 我使用的机器你使用的机器 是否在 同一个局域网 里,该怎么办?这时就需要使用到我们的 子网掩码

  相同的 子网掩码 就证明:我们使用的是 同一个局域网。这就是我们使用操作的一个介绍,我们首先要清楚它是 什么意思,干什么。至于后续的应用和操作,需要结合实际的需求在做延申和拓展。这一点需要各位读者朋友能注意一下。

  这里呢再给各位读者朋友做一个 拓展:如果你面试时遇到面试官问你什么是 网段地址?你可以回答:网段地址 是通过 子网掩码IP地址 进行 按位与 得来的。至于说什么是 按位与 ?这个 网段地址按位与 怎么运算?小编我也不太清楚,你也不用特别的 深挖,感兴趣的朋友可以自己去百度整合学习一下,顺带着把你的学习汇总和心得能够留在评论区,方便给更多的读者朋友进行普及和学习。

  

端口

  前面我给大家介绍 IP 的时候说过:IP 的作用就是用来寻找计算机的。我们现在已经理解计算机与计算机之间究竟是怎么 通过网络进行通讯 的。

  在开始介绍 端口 前,我想问大家一个问题:我想每位读者朋友应该都使用过 QQ,微信,淘宝,抖音…… 而且也都有自己的专属账号。小编我现在有个问题:如果我现在用QQ给你发了一条消息,你的微信能收到我通过QQ给你发的消息吗?

  我想,你一定不假思索的就会回答:当然是不可能了。但这是 为什么呢? 为什么你的手机能够收到我发你的消息,但是你却无法 通过微信 接收以及读取 到我 通过QQ 给你发的消息呢?

  首先我们要明确:小编我的QQ给你的QQ发送信息,你的QQ要能感应到小编我的QQ给你发的信息。这时,就需要到 端口 的作用了。

  所谓的 端口 就是为了 区分 各种 不同的客户端端口 的出现也是 广域网 正式完成搭建的一个 地标型标志

  

端口介绍

  前面我们说到:所谓的 端口 就是为了 区分 各种 不同的客户端端口 的出现也是 广域网 正式完成搭建的一个 地标型标志。那它究竟是怎么个 地标型标志 呢?接下来我们就 简单又不失详细的 来个各位读者朋友详细的介绍一下。

  

端口分类

  端口的作用 是用来 区分 不同的 客户端

  右键点击计算机桌面的 任务栏,点击 任务管理器,查看 任务管理器详细信息。如下图:

  任务管理器详细信息 里的 PID 就是 进程客户端端口编号。不过,这个 PID 产生的 端口编号 不是固定的,是在 进程客户端 开始运行时使用前 这个阶段 随机生成 的。

  OK,现在我们已经知道了 端口 的作用,接下来,我们来看看,我们日常使用的 客户端 是如何应用它们的 端口 的。

  想要保持两台计算机能 持续的互传信息,首先当然是要知道这条信息是 发给谁 dest_ip(目标IP),其次当然是需要对方知道知道 是谁发信息给你 scr_ip(源IP),在明确彼此的身份信息之后别忘了 那个谁的信息接收地址是多少 dest_port(目标端口)。只有满足了这 三个充分必要条件 才能保持两台计算机能 持续的互传信息

  简单的介绍完了如何保持两台计算机能 持续的互传信息 后,我们来简单的了解一下 端口 有哪些类型。

  端口 的类型分为 知名端口动态端口

  1. 知名端口(well known ports)
    • 80 端口分配给 HTTP服务
    • 21 端口分配给 FTP服务
    • 端口编号的范围是 从 0 到 1023

  2. 动态端口
    • 动态端口的范围是 1024 - 65535

  注意:
    • 在 同一时间 只会有 一个程序 占用 一个端口不可能同一个计算机同一时间两个程序 占用 一个端口

  

socket简介

TCP/IP协议

  TCP/IP 协议是 最基本网络通信协议,是 Transmission Control Protocol/Internet Protocol 的简写,即传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本的协议、Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP协议组成。TCP/IP 定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求。

  然而,TCP/IP协议 并不是 国际官方组织 制定的标准,而是 民间组织(一些大型国际厂商、高等院校)自行商定 的标准,因为更简便,推广力度更大,而成为了事实上的标准。

  TCP/IP 网络模型四层模型从根本上和OSI七层网络模型是一样的,只是合并了几层:

  在TCP/IP协议中,其各层之间的通信机制,大致如下图所示:


  现在市场之所以更多应用 TCP/IP协议 而较少的应用 UDP协议 是跟他们彼此的传输特性有着密不可分的关系的。

  第一点当然是通过 TCP/IP协议 传递的数据 更加的 安全

  第二点,通过 TCP/IP协议 进行的网络信息传递就像是 打电话约束着 彼此必须保持畅通的 一来一往 的信息传递;而通过 UDP协议 进行的网络信息传递就像是 发短信,虽然信息传输的速度更快,但信息反馈的效率却是不确定。这也是导致现在市场更多应用 TCP/IP协议 的原因。

  有关于对 网络通信协议 的学习,小编我在这里发表一个简单的个人理解:有关对 TCP/IP 的学习,只要从事编程工作的朋友都是要学的,也都是必须要学的很透彻的。不过,在从事编程的不同的阶段对 TCP/IP 学习的深度也是不同的。对于我们当前的阶段对 TCP/IP 的学习只要学习到当前的阶段就够了;知道 TCP/IP 是什么,对 TCP/IP 有个基础的认知,知道 TCP/IP 的基础使用 就够了。至于再深入的研究,需要结合后续对从事的深入和方向逐步的层层递进。不需要急于一时,一口气全部的吃透。

  以前,在这上面我曾深深的吃过亏。在此以我个人的经历给各位的读者一个小小的建议。

  更多的有关 TCP/IP协议 和 UDP协议 的详细内容,在此省略 两千万字,小编我就不在这浪费大家的阅读精力了,感兴趣的朋友可以自己去百度整合学习一下,顺带着把你的学习汇总和心得能够留在评论区,方便给更多的读者朋友进行普及和学习。

  

socket 介绍

  socket 又称 “套接字”,应用程序通常通过 “套接字” 向网络 发出请求 或者 应答网络请求,使 主机间 或者 一台计算机上的进程间 可以通讯

  我们可以把 socket 类比于我们的现在的 快递公司:我们 收发快递 的时候,我们只要把 货物 交给 快递公司快递公司 负责好货物的 收揽包装分发 到各个地方统一配送,在 目的地址配送员 接收快递配送员 联系 收件人,然后收件人 负责接收 就可以了。

  socket 也如此,我们将 数据 给了socket,然后 socket 通过 各种函数 实现 数据封装建立 目标主机 端口连接,在客户端的 socket 进行数据接收,交付主机

  白话说,socket 就是 两个节点 为了 互相通信,而在各自家里装的一部 ‘电话’。

  加入 socket 后,网络关系 如下图所示:

  我们一起来看一下 函数socket()

  函数 socket() 的源码太长了,我们先节选出它自动跳转的内容:

class socket(_socket.socket):

    """A subclass of _socket.socket adding the makefile() method."""

    __slots__ = ["__weakref__", "_io_refs", "_closed"]

    def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None):
        # For user code address family and type values are IntEnum members, but
        # for the underlying _socket.socket they're just integers. The
        # constructor of _socket.socket converts the given argument to an
        # integer automatically.
        _socket.socket.__init__(self, family, type, proto, fileno)
        self._io_refs = 0
        self._closed = False

  函数 socket() 中形参的注释:

   family:地址族;协议族;对于TCP/IP协议族通常指定为 AF_INET; 这个属性在 JAVA 还是 PHP 里都是有的。

family 参数描述
socket.AF_UNIX只能够用于单一的Unix系统进程间通信
socket.AF_INET服务器之间网络通信
socket.AF_INET6IPv6

  看完我对 函数 socket() 中的形参 family 的介绍后,一定有读者朋友会问了:我记得每个 地址族 都有它们特定的编号;我们在定义 地址族 的时候是否能用这些 地址族编号 对形参 family 进行定义呢?

  在这里呢,小编我也简单的罗列了一些 地址族编号

AF_APPLETALK = 16
AF_DECnet = 12
AF_INET = 2
AF_INET6 = 23
AF_IPX = 6
AF_IRDA = 26
AF_SNA = 11
AF_UNSPEC = 0

  使用 地址族编号 编辑代码并不是不可以,毕竟 地址族 == 编号;但是我们在我们参与项目开发的时候写的代码或端口却又不能使用这些 编号,原因无他,因为别人不知道你这个 编号 到底哦是什么。

   type:套接字类型;默认值为 SOCK_STREAMSOCK_STREAMTCP流式套接字;UDP流式套接字SOCK_DGRAML

type 参数描述
socket.SOCK_STREAM流式socket , 当使用TCP时选择此参数
socket.SOCK_DGRAM数据报式socket ,当使用UDP时选择此参数
socket.SOCK_RAW原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。

   proto:指明所要接收的协议类型,通常为0或者不填。

proto 参数描述
socket.IPPROTO_RAW相当于protocol=255,此时socket只能用来发送IP包,而不能接收任何的数据。发送的数据需要自己填充IP包头,并且自己计算校验和
socket.IPPROTO_IP相当于protocol=0,此时用于接收任何的IP数据包。其中的校验和和协议分析由程序自己完成。

  创建 套接字 参考实例:

   创建TCP Socket:s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

   创建UDP Socket:s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

  

  附:socket 相关的函数

socket函数描述函数类型
s.bind(address)将套接字绑定到地址, 在AF_INET下,以元组(host,port)的形式表示地址。服务端函数
s.listen(backlog)开始监听TCP传入连接。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。服务端函数
s.accept()接受TCP连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。服务端函数
s.connect(address)连接到address处的套接字。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。客户端函数
s.connect_ex(adddress)功能与connect(address)相同,但是成功返回0,失败返回error的值。客户端函数
s.recv(bufsize[,flag])接受TCP套接字的数据。数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。公共函数
s.send(string[,flag])发送TCP数据。将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。公共函数
s.sendall(string[,flag])完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。公共函数
s.recvfrom(bufsize[.flag])接受UDP套接字的数据。与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。公共函数
s.sendto(string[,flag],address)发送UDP数据。将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。公共函数
s.close()关闭套接字。公共函数
s.getpeername()返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。公共函数
s.getsockname()返回套接字自己的地址。通常是一个元组(ipaddr,port),公共函数
s.setsockopt(level,optname,value)设置给定套接字选项的值。公共函数
s.getsockopt(level,optname[.buflen])返回套接字选项的值。公共函数
s.settimeout(timeout)设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect())公共函数
s.gettimeout()返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。公共函数
s.fileno()返回套接字的文件描述符。公共函数
s.setblocking(flag)如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。公共函数
s.makefile()创建一个与该套接字相关连的文件。公共函数

  

UDP 发送与接收数据

udp发送数据

  udp发送数据的实现步骤
   • 1. 创建套接字
   • 2. 使用套接字收/发数据
   • 3. 关闭套接字

  前面我们已经把 套接字函数socket 详细的介绍过了,也已经知道 udp发送数据的实现步骤;那么我们就先把最简单的 第1步. 创建套接字 和 第3步. 关闭套接字 来写一个 参考实例:

import socket             # 内置模块

# 1.创建套接字             # 打开冰箱
udp_socket = socket.socket(family = socket.AF_INET, type = socket.SOCK_DGRAM)

# 2.使用套接字收/发数据     # 把大象塞进去


# 3.关闭套接字             # 关闭冰箱
udp_socket.close()

  上面的这个 参考实例 虽然没有很多太多的铺垫,但是详细具体的意思,我想各位读者朋友应该也没什么疑问。函数close() 也是一个老函数了,对于它的印象,我也只是记得我在前面的文章里介绍过,不过,具体是哪篇文章,小编我已经记得不太清了。

  接下来我们来详细的讲讲这个 第2步. 使用套接字发数据

  在我们通常的编程方式中有 函数式编程 也有 面向对象式编程;不过在编辑 使用套接字发数据 的时候,不需要用 面向对象式编程,使用 函数式编程 会更加的方便。

  在开始给大家介绍 使用套接字发数据 之前呢,先带大家一起回顾一下 面向对象编程

  参考实例:

class Deom(object):
    def __init__(self, ):
        pass

    def test(self):
        pass

    def main(self):
        pass
    
	# or

    def run(self):
        pass
    
if __name__ == '__main__':		# main + 回车键
	d = Deom()
	d.test()
	d.run()

  对于上面的这个 参考实例 的内容,我想读者朋友你应该并不陌生。我们自定义了一个名叫 Deom 的类,类中除了常规的 魔术方法 __init__(self, ) 还有一个 类方法test,为了方便 类与类之间的互相访问,我们还特地的添加了一个 类方法main / run 以实现 对类的内部访问 或者 类对外部的访问,然后我们可以通过 main方法 这个入口来进行对类的实例化或者调用等等的操作。最后在 main方法 里直接对我们这个 自定义类Deom 进行实例化,最后直接再调用 自定义类Deom 里的方法就可以了。

  通过 main方法 调用的函数的主要逻辑还是在 中,不会再给外面带来一系列的冗余。

  对于这个访问方法有的程序是 run,这只是名字不同而已,但是通常一个系列的类,都有它们主打的 入口方法

  不过,我们前面也说了:在编辑 使用套接字发数据 的时候,不需要用 面向对象式编程,使用 函数式编程 会更加的方便。那我们就也简单的介绍一下 main方法 对函数的应用:

  参考实例:

def main(self):
	pass

if __name__ == '__main__':		# main + 回车键
	main()

  如果我们想要主程序里的函数,只要直接在 main方法 下调用就可以了。

  接下来我们就开始使用 函数式编程 编辑 第2步. 使用套接字发数据

  在开始讲解 第2步. 使用套接字发数据 之前,小编建议各位读者朋友现在自己的电脑上安装好 网络调试助手 这款软件。提取码:kjis

  对于 网络调试助手 的使用,在此省略 两千万字,最需要大家注意的就是 协议类型本地主机地址本地主机端口 这三个 设置栏;其他内容小编我就不在这浪费大家的阅读精力了,感兴趣的朋友可以自己去百度整合学习一下,顺带着把你的学习汇总和心得能够留在评论区,方便给更多的读者朋友进行普及和学习。

  下载安装好 网络调试助手 后,接下来,我们就一起来看看 套接字收/发数据 的方法 sendto() 该怎么使用。

  既然已经知道 套接字收/发数据 的方法是 sendto(),那么毫无疑问,就先把 套接字收/发数据 这块空缺给补上。

import socket             # 内置模块

# 1.创建套接字             # 打开冰箱
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 2.使用套接字收/发数据     # 把大象塞进去
udp_socket.sendto()

# 3.关闭套接字             # 关闭冰箱
udp_socket.close()

  套接字收/发数据 这块空缺已经补上了,但是这个方法 sendto() 到底该怎么使用,我们现在还是不知道呢。不知道怎么使用不可怕,前面我们说过:不知道方法的使用方法,直接就去看源码。

@overload
def sendto(self, data: bytes, address: _Address) -> int: ...
@overload
def sendto(self, data: bytes, flags: int, address: _Address) -> int: ...
def setblocking(self, flag: bool) -> None: ...
def settimeout(self, value: Optional[float]) -> None: ...
def setsockopt(self, level: int, optname: int, value: Union[int, bytes]) -> None: ...
def shutdown(self, how: int) -> None: ...

  方法 sendto() 的源码还是比较好找的,不用转来转去的找。既然找到了,那就开始转译了。

  我们先别 一个字一个字 的看,我们先 一圈一圈 的看。

  先看最外圈:def sendto() -> int: ...;方法 sendto() 最后输出的是一串 整形字符串。我的这个转译没什么问题哦,如果有什么错误的还请您能在本文的评论区留言。

  最外圈的看完了,我们再往里圈看:方法 sendto() 有三个形参,分别是 selfdataaddress。先别关注形参后面跟的 ,我们先来看看这三个形参分别都是什么意思:self 这个就不需要再重复解释了,大家都是老朋友了,方法的 默认参数data 的意思是 数据address 的意思是 地址

  最后,我们再来看看形参 dataaddress 后面跟的值是什么意思:参数data 后面跟的 bytes 不是什么值,而是一个 数据类型,这个参数传入的数据类型要为 字节型;参数address 地址 后面跟的 有点看不明白,不过不要紧,我们再看看这个 是否有隐藏了什么信息,继续深挖果然还有一小节的隐藏信息 _Address = Union[tuple, str],这个地址是由 [元组, 字符串] 两个集合的并集。一些表达上的细节,大家就不要太在意了,意会,意会 😃

  通过上面的这一番拆解,我们现在已经大致的知道 方法sendto() 的使用方法了,接下来,我们就一起来完成 完善方法sendto() 这最后的一块拼图。

import socket             # 内置模块

# 1.创建套接字             # 打开冰箱
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 2.使用套接字收/发数据     # 把大象塞进去
# data: bytes  address: tuple
udp_socket.sendto("nihao", ("192.168.1.7", 8080))

# 3.关闭套接字             # 关闭冰箱
udp_socket.close()

  既然,我们现在已经完成了使用 内置类socket 进行 udp发送数据 的拼图,我们就一起来看看最后的运行结果:

   TypeError: a bytes-like object is required, not 'str'

   报错?为什么会报错?而且还有:这个报错到底是什么意思?

  我们先一起来看看错误的源码:

Traceback (most recent call last):
  File "G:/lianxi/zhong_ji_ban/测试.py", line 8, in <module>
    udp_socket.sendto("nihao", ("192.168.31.12", 8080))
TypeError: a bytes-like object is required, not 'str'

  出错的地方是 第8行;错误的意思是:传入的对象类型应该是 bytes-like 类型,而不是 str 类型。

  那我们就把 第8行 传入数据类型的数据类型转换一下

  udp发送数据 的详细内容:

import socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.sendto(b"nihao", ("192.168.31.12", 8080))
udp_socket.close()

  虽然操作台最后没返回任何的信息,但这也是一个好的信息:这证明我们的操作都是正确的。

  此时,我们再看 网络调试助手 大家就会发现:


  之前一片空白的 数据日志 上出现了第一组数据。

  

Udp接收数据

  介绍完了 Udp发送数据,接下来我们就一起来看看 Udp接收数据 又该如何实现。

  我们先来了解一下 Udp接收数据 的实现步骤:
   • 1.创建套接字
   • 2.绑定本地信息(IP和端口)
   • 3.接受数据
   • 4.打印数据
   • 5.关闭套接字

  老样子,前面我们已经把 套接字函数socket 详细的介绍过了,也已经知道 udp发送数据的实现步骤;那么我们就先把最简单的 第1步. 创建套接字 和 第2步. 关闭套接字 来写一个 参考实例:

import socket             # 内置模块

# 1.创建套接字             # 打开冰箱
udp_socket = socket.socket(family = socket.AF_INET, type = socket.SOCK_DGRAM)

# 2.绑定本地信息(IP和端口)


# 3.接受数据


# 4.打印数据


# 5.关闭套接字             # 关闭冰箱
udp_socket.close()

  上面的这个 参考实例 虽然没有很多太多的铺垫,但是详细具体的意思,我想各位读者朋友应该也没什么疑问。函数close() 也是一个老函数了,对于它的印象,我也只是记得我在前面的文章里介绍过,不过,具体是哪篇文章,小编我已经记得不太清了。

import socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
bind_addr = ("", 7788)     
udp_socket.bind(bind_addr) 
recv_data = udp_socket.recvfrom(1024)
udp_socket.close()

udp聊天器

  udp聊天器的实现步骤:
   • 1.创建套接字 套接字是可以同时收发数据的
   • 2.发送数据
   • 3.接收数据

  
  
  

总结小便条

本篇文章主要讲了以下几点内容:

  

  本章回顾暂时就到这了,如果还有点晕,那就把文章里所有引用的案例代码再敲几遍吧。拜拜~

更多推荐

25. Python语言 Web 开发 之 Socket 编程 · 第一章 UDP发送与接收数据

本文发布于:2023-04-19 03:27:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/f758409c6e7ac4f0371f523a9eea5516.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:语言   数据   Python   UDP   Socket

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!

  • 87079文章数
  • 19105阅读数
  • 0评论数