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脚本来实现最简单的FTP下载的教程
May 04 Python
实践Python的爬虫框架Scrapy来抓取豆瓣电影TOP250
Jan 20 Python
Python合并字典键值并去除重复元素的实例
Dec 18 Python
详解 Python 与文件对象共事的实例
Sep 11 Python
Python编程pygal绘图实例之XY线
Dec 09 Python
python 中if else 语句的作用及示例代码
Mar 05 Python
python实现微信自动回复功能
Apr 11 Python
Python提取PDF内容的方法(文本、图像、线条等)
Sep 25 Python
python 使用递归回溯完美解决八皇后的问题
Feb 26 Python
python topk()函数求最大和最小值实例
Apr 02 Python
Python浮点型(float)运算结果不正确的解决方案
Sep 22 Python
python RSA加密的示例
Dec 09 Python
python cv2图像质量压缩的算法示例
Jun 04 #Python
高考要来啦!用Python爬取历年高考数据并分析
单身狗福利?Python爬取某婚恋网征婚数据
告别网页搜索!教你用python实现一款属于自己的翻译词典软件
Python 中random 库的详细使用
Jun 03 #Python
详解Python常用的魔法方法
Python自动化之批量处理工作簿和工作表
Jun 03 #Python
You might like
咖啡风味 世界咖啡主要分布分布 咖啡的生长要求
2021/03/06 新手入门
php设计模式 DAO(数据访问对象模式)
2011/06/26 PHP
Zend的Registry机制的使用说明
2013/05/02 PHP
php构造方法中析构方法在继承中的表现
2016/04/12 PHP
laravel 验证错误信息到 blade模板的方法
2019/09/29 PHP
js控制的回到页面顶端goTop的代码实现
2013/03/20 Javascript
table对象中的insertRow与deleteRow使用示例
2014/01/26 Javascript
JS判断文本框内容改变事件的简单实例
2014/03/07 Javascript
js实现百度联盟中一款不错的图片切换效果完整实例
2015/03/04 Javascript
jQuery获取标签文本内容和html内容的方法
2015/03/27 Javascript
JavaScript仿静态分页实现方法
2015/08/04 Javascript
javascript弹出窗口中增加确定取消按钮
2016/06/24 Javascript
jQuery的图片轮播插件PgwSlideshow使用详解
2016/08/11 Javascript
jQuery post数据至ashx实例详解
2016/11/18 Javascript
Vue监听数据对象变化源码
2017/03/09 Javascript
使用jQuery和ajax代替iframe的方法(详解)
2017/04/12 jQuery
微信小程序与php 实现微信支付的简单实例
2017/06/23 Javascript
基于vue2实现左滑删除功能
2017/11/28 Javascript
解决Vue开发中对话框被遮罩层挡住的问题
2018/11/26 Javascript
浅谈layui分页控件field参数接收对象的问题
2019/09/20 Javascript
在elementui中Notification组件添加点击事件实例
2020/11/11 Javascript
Python实现获取某天是某个月中的第几周
2015/02/11 Python
python根据给定文件返回文件名和扩展名的方法
2015/03/27 Python
深入浅析Python字符编码
2015/11/12 Python
Django Admin 实现外键过滤的方法
2017/09/29 Python
django.db.utils.ProgrammingError: (1146, u“Table‘’ doesn’t exist”)问题的解决
2018/07/13 Python
Python面向对象之类的内置attr属性示例
2018/12/14 Python
Django框架使用内置方法实现登录功能详解
2019/06/12 Python
python双端队列原理、实现与使用方法分析
2019/11/27 Python
Flask中endpoint的理解(小结)
2019/12/11 Python
详解opencv中画圆circle函数和椭圆ellipse函数
2019/12/27 Python
移动端Html5中百度地图的点击事件
2019/01/31 HTML / CSS
国际会计专业求职信
2014/08/04 职场文书
学生顶撞老师的检讨书
2014/09/17 职场文书
纯html+css实现奥运五环的示例代码
2021/08/02 HTML / CSS
python中validators库的使用方法详解
2022/09/23 Python