Python实现socket库网络通信套接字


Posted in Python onJune 04, 2021

Socket 套接字:通讯端点 简介

socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。

Socket 是任何一种计算机网络通讯中最基础的内容。Socket通讯一般用户C/S结构系统的网络通讯。

Socket 网络通讯是基于TCP(传输控制协议)或UDP(用户数据报协议)两种协议通讯,所以有 面向连接(TCP )与无连接(UDP ) 两种通讯方式。

Python 要创建TCP 套接字就得在创建的时候,指定套接字类型为SOCK_STREAM,它使用 TCP/IP通讯协议。

Socket网络通信套接字

socket库提供了一个底层C API,可以使用BSD套接字接口实现网络通信。它包括socket类,用于处理具体的数据通道,还包括用来完成网络相关任务的函数,如将一个服务器名转换为一个地址以及格式化数据以便在网络上发送。

什么是套接字?

套接字是程序在本地或者通过互联网来回传递数据时所用通信通道的一个端点。

套接字有2个主要属性用于控制如何发送数据:地址簇(address family)控制所用的OSI网络层协议;套接字类型(socket type)控制传输层协议。(参考《计算机网络》7层协议)

地址簇

Python支持3个地址簇:

  • AF_INET:用于IPv4寻址。IPv4长度为4个字节,通常表示为4个数的序列,每个字节对应一个数,用点号分割(如121.63.0.243)。这些值通常被称为IP地址。目前IPv4依旧还是主流。
  • AF_INET6:用于IPv6寻址。目前IPv6已经小范围应用,它支持128位地址和通信流调整,还支持IPv4不支持的一些路由特性。
  • AF_UNIX:用于UNIX域套接字(UDS)的地址簇,这是一种POSIX兼容系统上的进程间通信协议。UDS的实现通常允许操作系统直接从进程向进程间传递数据,而不用通过网络栈。这比使用AF_INET更高效,但是由于要用到文件系统作为寻址的命令空间,所以UDS仅限于同一个系统上的进程。

套接字类型

套接字类型有两种:

  • SOCK_DGRAM:面向消息的数据报传输,数据报套接字通常与UDP关联,即用户数据报协议。这些套接字能提供不可靠的消息传送。
  • SOCK_STREAM:面向流的传输,与TCP相关,即传输控制协议。它们可以在客户和服务器之间提供字节流,通过超时管理,重传和其他特性确保提供消息传送或失败通知。

大多数应用协议(如HTTP)都建立在TCP基础上,因为这样更容易创建自动处理消息排序和传送的复杂应用。

UDP通常用于顺序不太重要的协议(如DNS交换)。UDP与TCP都支持IPv4与IPv6。

套接字的简单应用

gethostbyname_ex()与gethostbyname()

socket库包含一些与网络上的域名服务交互的函数,比如解析域名为IP地址可以用到gethostbyname_ex(),示例如下:

import socket

host_str = [
    'www.baidu.com',
    'cloud.tencent.com',
    'www.csdn.net'
]
for host in host_str:
    try:
        name, aliases, addresses = socket.gethostbyname_ex(host)
        print(host)
        print("主机名:", name)
        print("所有别名:", aliases)
        print("所有可用IP地址:", addresses)
    except socket.error as msg:
        print(host, msg)

运行之后,效果如下:

Python实现socket库网络通信套接字

gethostbyname_ex:该函数返回3个参数,主机名,别名,以及解析能跳转到当前主机的IP地址。

gethostbyname:类似的函数,只返回当前主机的IP地址。

getservbyname()与getservbyport()

socket库提供getservbyname()函数用于查找网络服务的端口号和标准名,示例如下所示:

import socket
from urllib.parse import urlparse

url_str = [
    'https://www.baidu.com',
    'https://www.csdn.net',
    'smtp://smtp.qq.com',
]
for url in url_str:
    try:
        parsed_url = urlparse(url)
        port = socket.getservbyname(parsed_url.scheme)
        print(url)
        print("端口号:", port)
    except socket.error as msg:
        print(url, msg)

运行之后,效果如下:

Python实现socket库网络通信套接字

当然,其实最有用的并不是给定一个链接去查询端口号,而是逆向操作。(因为标准化服务端口号一般都是固定的)

socket库提供getservbyport()函数用于完成逆向的服务端口查找,示例代码如下所示:

import socket

url = '{}://smtp.qq.com'.format(socket.getservbyport(25))
print(url)

运行之后,效果如下:

Python实现socket库网络通信套接字

getprotobyname()

socket库还可以使用getprotobyname()函数获取分配给一个传输协议的端口号,示例如下:

import socket

#获取匹配开头字符串的所有属性值
def getConstants(prefix):
    return {
        getattr(socket, n): n
        for n in dir(socket)
        if n.startswith(prefix)
    }
ipproto_str = getConstants("IPPROTO_")
for agree in ['tcp', 'udp']:
    num = socket.getprotobyname(agree)
    name = ipproto_str[num]
    print(name, num)

运行之后,效果如下:

Python实现socket库网络通信套接字

对于协议码,在程序定义中一般都是标准化常量,这就是意味着,它们的常量名都有一定的规律,而socket协议码前缀是IPPROTO_。

getaddrinfo(查找服务器地址)

getaddrinfo()函数用于将一个服务的基本地址转换为一个元组列表,其中包含建立一个连接所需要的全部信息。比如其网络簇与协议等,示例如下:

import socket

# 获取匹配开头字符串的所有属性值
def getConstants(prefix):
    return {
        getattr(socket, n): n
        for n in dir(socket)
        if n.startswith(prefix)
    }
ipproto_str = getConstants("IPPROTO_")
family_str = getConstants("AF_")
type_str = getConstants("SOCK_")
for response in socket.getaddrinfo('www.csdn.net', 'http', family=socket.AF_INET, type=socket.SOCK_STREAM,
                                   proto=socket.IPPROTO_TCP, flags=socket.AI_CANONNAME):
    family, socktype, ipproto, canonname, sockaddr = response
    print("地址簇:       ", family_str[family])
    print("套接字类型:    ", type_str[socktype])
    print("协议码:       ", ipproto_str[ipproto])
    print("主机规范名:    ", canonname)
    print("ip地址与端口号:", sockaddr)

运行之后,效果如下:

Python实现socket库网络通信套接字

这里如果只用socket.getaddrinfo(‘www.csdn.net', ‘http'),表示不需要过滤任何连接信息,但大型的网站一般都有几个IP或者域名跳转到主页的。

所以通过后面的参数,可以筛选自己需要的链接信息。

其中,最后一个参数socket.AI_CANONNAME表示如果主机有别名,那么结果中会包含服务器的标准名。所有没有这个标志,标准名为空。

IP地址的表示方式

如果读者有C的经验,那么肯定知道,通过C语言编写的套接字程序是使用struct sockaddr结构体,它将IP地址表示为二进制,而不是上面显示的Python字符串形式。

如果想在Python和C之间转换IPv4地址,可以使用inet_aton()和inet_ntoa()。示例如下:

import socket
import binascii

ip_list = [
    "192.168.50.1",
    "127.0.0.1"
]
for ip in ip_list:
    packed = socket.inet_aton(ip)
    print("原始字符串ip地址:", ip)
    print("C库能识别的ip地址", binascii.hexlify(packed))
    print("还原C库ip地址字符串", socket.inet_ntoa(packed))
    print()

运行之后,效果如下:

Python实现socket库网络通信套接字

inet_pton()与inet_ntop()

相信读者如果在测试上面代码,那么输入上面inet_aton()函数时,一定看到提醒中还有inet_pton()与inet_ntop()函数。

这2个函数既能处理IPv4也能处理IPv6,而inet_aton()和inet_ntoa()只能处理IPv4。它们的使用方式如下:

import socket
import binascii

ipv6_str = "2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b"
packed = socket.inet_pton(socket.AF_INET6, ipv6_str)
print("原始字符串ip地址:", ipv6_str)
print("C库能识别的ip地址", binascii.hexlify(packed))
print("还原C库ip地址字符串", socket.inet_ntop(socket.AF_INET6, packed))
print()

ipv4_str = "192.168.50.1"
packed = socket.inet_pton(socket.AF_INET, ipv4_str)
print("原始字符串ip地址:", ipv4_str)
print("C库能识别的ip地址", binascii.hexlify(packed))
print("还原C库ip地址字符串", socket.inet_ntop(socket.AF_INET, packed))
print()

运行之后,效果如下:

Python实现socket库网络通信套接字

以上就是Python实现socket库网络通信套接字的详细内容,更多关于Python socket库的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
Python简单检测文本类型的2种方法【基于文件头及cchardet库】
Sep 18 Python
Django与JS交互的示例代码
Aug 23 Python
Django实现快速分页的方法实例
Oct 22 Python
Python实现打印螺旋矩阵功能的方法
Nov 21 Python
python的numpy模块安装不成功简单解决方法总结
Dec 23 Python
TensorFlow saver指定变量的存取
Mar 10 Python
python 显示数组全部元素的方法
Apr 19 Python
django进阶之cookie和session的使用示例
Aug 17 Python
Python使用matplotlib 模块scatter方法画散点图示例
Sep 27 Python
python 创建一维的0向量实例
Dec 02 Python
基于python实现matlab filter函数过程详解
Jun 08 Python
python中执行smtplib失败的处理方法
Jul 01 Python
python cv2图像质量压缩的算法示例
Jun 04 #Python
高考要来啦!用Python爬取历年高考数据并分析
单身狗福利?Python爬取某婚恋网征婚数据
告别网页搜索!教你用python实现一款属于自己的翻译词典软件
Python 中random 库的详细使用
Jun 03 #Python
详解Python常用的魔法方法
Python自动化之批量处理工作簿和工作表
Jun 03 #Python
You might like
PHP XML备份Mysql数据库
2009/05/27 PHP
如何给phpcms v9增加类似于phpcms 2008中的关键词表
2013/07/01 PHP
PHP中使用sleep函数实现定时任务实例分享
2014/08/21 PHP
php中ltrim()、rtrim()与trim()删除字符空格实例
2014/11/25 PHP
PHP中preg_match函数正则匹配的字符串长度问题
2015/05/27 PHP
PHP实现mysqli批量执行多条语句的方法示例
2017/07/22 PHP
php大小写转换函数(strtolower、strtoupper)用法介绍
2017/11/17 PHP
Laravel数据库读写分离配置的方法
2019/10/13 PHP
Thinkphp 框架扩展之驱动扩展实例分析
2020/04/27 PHP
基于php解决json_encode中文UNICODE转码问题
2020/11/10 PHP
JavaScript实现动态增加文件域表单
2009/02/12 Javascript
锋利的jQuery 要点归纳(一) jQuery选择器
2010/03/21 Javascript
javascript Array对象基础知识小结
2010/11/16 Javascript
深入解析Javascript闭包的功能及实现方法
2016/07/10 Javascript
jQuery插件FusionCharts绘制的2D帕累托图效果示例【附demo源码】
2017/03/28 jQuery
vue.js中父组件调用子组件的内部方法示例
2017/10/22 Javascript
详解基于vue-cli3.0如何构建功能完善的前端架子
2018/10/09 Javascript
Vue.js watch监视属性知识点总结
2019/11/11 Javascript
如何优雅地在Node应用中进行错误异常处理
2019/11/25 Javascript
Python使用修饰器执行函数的参数检查功能示例
2017/09/26 Python
Python实现两个list求交集,并集,差集的方法示例
2018/08/02 Python
python读取txt文件中特定位置字符的方法
2018/12/24 Python
Python Django框架单元测试之文件上传测试示例
2019/05/17 Python
在python中画正态分布图像的实例
2019/07/08 Python
Python中的类与类型示例详解
2019/07/10 Python
python按行读取文件并找出其中指定字符串
2019/08/08 Python
Python netmiko模块的使用
2020/02/14 Python
pycharm运行程序时看不到任何结果显示的解决
2020/02/21 Python
匡威俄罗斯官网:Converse俄罗斯
2020/05/09 全球购物
工程现场管理求职自荐信
2013/10/02 职场文书
交通事故调解协议书
2014/04/16 职场文书
提拔干部考察材料
2014/05/26 职场文书
2014年保险业务员工作总结
2014/12/23 职场文书
三八红旗手事迹材料
2014/12/26 职场文书
财务总监岗位职责范本
2015/04/03 职场文书
Java数组与堆栈相关知识总结
2021/06/29 Java/Android