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程序中使用SQLAlchemy时出现乱码的解决方案
Apr 24 Python
Python脚本实现虾米网签到功能
Apr 12 Python
Python学习笔记之解析json的方法分析
Apr 21 Python
python中virtualenvwrapper安装与使用
May 20 Python
PyCharm代码格式调整方法
May 23 Python
Django框架的使用教程路由请求响应的方法
Jul 03 Python
Flask框架学习笔记之消息提示与异常处理操作详解
Aug 15 Python
基于Python的微信机器人开发 微信登录和获取好友列表实现解析
Aug 21 Python
使用python检查yaml配置文件是否符合要求
Apr 09 Python
Mac PyCharm中的.gitignore 安装设置教程
Apr 16 Python
django 数据库返回queryset实现封装为字典
May 19 Python
Python日志打印里logging.getLogger源码分析详解
Jan 17 Python
python cv2图像质量压缩的算法示例
Jun 04 #Python
高考要来啦!用Python爬取历年高考数据并分析
单身狗福利?Python爬取某婚恋网征婚数据
告别网页搜索!教你用python实现一款属于自己的翻译词典软件
Python 中random 库的详细使用
Jun 03 #Python
详解Python常用的魔法方法
Python自动化之批量处理工作簿和工作表
Jun 03 #Python
You might like
全国FM电台频率大全 - 20 广西省
2020/03/11 无线电
新安装的MySQL数据库需要注意的安全知识
2008/07/30 PHP
PHP中strtotime函数使用方法详解
2011/11/27 PHP
php-cli简介(不会Shell语言一样用Shell)
2013/06/03 PHP
php中socket通信机制实例详解
2015/01/03 PHP
PHP中set error handler函数用法小结
2015/11/11 PHP
php时间计算相关问题小结
2016/05/09 PHP
JavaScript入门教程(9) Document文档对象
2009/01/31 Javascript
js获取判断上传文件后缀名的示例代码
2014/02/19 Javascript
JS取得绝对路径的实现代码
2015/01/16 Javascript
跟我学习javascript的最新标准ES6
2015/11/20 Javascript
基于Bootstrap的Metronic框架实现页面链接收藏夹功能
2016/08/29 Javascript
Jquery EasyUI Datagrid右键菜单实现方法
2016/12/30 Javascript
正则验证小数点后面只能有两位数的方法
2017/02/28 Javascript
react-navigation 如何判断用户是否登录跳转到登录页的方法
2017/12/01 Javascript
web前端vue实现插值文本和输出原始html
2018/01/19 Javascript
React如何实现浏览器打印部分内容详析
2019/05/19 Javascript
vue中如何添加百度统计代码
2020/12/19 Vue.js
python抓取豆瓣图片并自动保存示例学习
2014/01/10 Python
Windows 64位下python3安装nltk模块
2018/09/19 Python
python中的数据结构比较
2019/05/13 Python
python绘制已知点的坐标的直线实例
2019/07/04 Python
详解Matplotlib绘图之属性设置
2019/08/23 Python
基于MSELoss()与CrossEntropyLoss()的区别详解
2020/01/02 Python
施华洛世奇巴西官网:SWAROVSKI巴西
2019/12/03 全球购物
与UNIX有关的几个名词
2015/09/17 面试题
行政工作个人的自我评价
2014/02/13 职场文书
教师考核评语
2014/04/28 职场文书
玩手机检讨书1000字
2014/10/20 职场文书
体育活动总结
2015/02/04 职场文书
2015年管理人员工作总结
2015/05/13 职场文书
2015年三年级班主任工作总结
2015/05/21 职场文书
热爱劳动主题班会
2015/08/14 职场文书
小数乘法教学反思
2016/02/22 职场文书
导游词之太行山青龙峡
2020/01/14 职场文书
Python爬取科目四考试题库的方法实现
2021/03/30 Python