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之总结参数的传递
Oct 10 Python
详解Python中用于计算指数的exp()方法
May 14 Python
Android基于TCP和URL协议的网络编程示例【附demo源码下载】
Jan 23 Python
Python中将变量按行写入txt文本中的方法
Apr 03 Python
Python中is和==的区别详解
Nov 15 Python
python+ffmpeg批量去视频开头的方法
Jan 09 Python
python实现抽奖小程序
Apr 15 Python
python傅里叶变换FFT绘制频谱图
Jul 19 Python
TFRecord文件查看包含的所有Features代码
Feb 17 Python
Django 博客实现简单的全文搜索的示例代码
Feb 17 Python
pytorch显存一直变大的解决方案
Apr 08 Python
Python实现byte转integer
Jun 03 Python
python cv2图像质量压缩的算法示例
Jun 04 #Python
高考要来啦!用Python爬取历年高考数据并分析
单身狗福利?Python爬取某婚恋网征婚数据
告别网页搜索!教你用python实现一款属于自己的翻译词典软件
Python 中random 库的详细使用
Jun 03 #Python
详解Python常用的魔法方法
Python自动化之批量处理工作簿和工作表
Jun 03 #Python
You might like
一些使用频率比较高的php函数
2008/10/03 PHP
在smarty中调用php内置函数的方法
2013/02/07 PHP
解析在zend Farmework下如何创立一个FORM表单
2013/06/28 PHP
Nginx+php配置文件及原理解析
2020/12/09 PHP
jQuery MD5加密实现代码
2010/03/15 Javascript
jQuery Ajax 仿AjaxPro.Utility.RegisterTypeForAjax辅助方法
2011/09/27 Javascript
jquery 操作DOM案例代码分享
2012/04/05 Javascript
JS数组的常见用法实例
2015/02/10 Javascript
JS拖动鼠标画出方框实现鼠标选区的方法
2015/08/05 Javascript
全面解析Bootstrap手风琴效果
2020/04/17 Javascript
javascript实现dom元素可拖动
2016/03/21 Javascript
jquery实现下拉框左右选择功能
2017/02/21 Javascript
Angular.js中处理页面闪烁的方法详解
2017/03/09 Javascript
详解微信小程序设置底部导航栏目方法
2017/06/29 Javascript
bootstrap实现二级下拉菜单效果
2017/11/23 Javascript
jQuery 实现批量提交表格多行数据的方法
2018/08/09 jQuery
JavaScript跳出循环的三种方法(break, return, continue)
2019/07/30 Javascript
微信小程序开发之转发分享功能
2019/10/22 Javascript
[02:11]2014DOTA2 TI专访VG战队Fenrir:队伍气氛良好
2014/07/11 DOTA
从零学Python之hello world
2014/05/21 Python
详细探究Python中的字典容器
2015/04/14 Python
Python实现的生产者、消费者问题完整实例
2018/05/30 Python
Flask框架通过Flask_login实现用户登录功能示例
2018/07/17 Python
pycharm配置pyqt5-tools开发环境的方法步骤
2019/02/11 Python
基于Python函数和变量名解析
2019/07/19 Python
基于Pycharm加载多个项目过程图解
2020/01/19 Python
python实现简单俄罗斯方块
2020/03/13 Python
python代数式括号有效性检验示例代码
2020/10/04 Python
如何用Python和JS实现的Web SSH工具
2021/02/23 Python
医院护士的求职信范文
2013/12/26 职场文书
社区学习雷锋活动总结
2014/04/25 职场文书
2014年企业工会工作总结
2014/11/12 职场文书
2015年小学语文教师工作总结
2015/10/23 职场文书
实习报告怎么写
2019/06/20 职场文书
PostgreSQL聚合函数介绍以及分组和排序
2022/04/12 PostgreSQL
详解PyTorch模型保存与加载
2022/04/28 Python