Python3 网络套接字(socket / socketserver)

2023-10-17 07:48

本文主要是介绍Python3 网络套接字(socket / socketserver),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Python3 网络套接字(socket / socketserver)


本文由 Luzhuo 编写,转发请保留该信息.
原文: http://blog.csdn.net/Rozol/article/details/72553736


以下代码以Python3.6.1为例
Less is more!

socket

#!/usr/bin/env python
# coding=utf-8
__author__ = 'Luzhuo'
__date__ = '2017/5/13'
# socket_demo.py 套接字接口
# 协议: TCP/IP(3次握手,4次断开) UDP(直接发数据)
# 一台PC最多可开 65535 个端口import socket
import os# 地址簇
socket.AF_INET  # IPV4, (host, port), host:'luzhuo.me' / '127.0.0.1'
socket.AF_INET6  # IPV6, (host, port, flowinfo, scopeid); boolean = socket.has_ipv6 // 是否支持ipv6# 套接字类型
socket.SOCK_STREAM  # tcp
socket.SOCK_DGRAM  # udp
socket.SOCK_RAW  # 原始套接字(可伪造IP地址,发起DDOS攻击)
socket.SOCK_RDM  # UDP,保证交付,但不保证顺序
socket.SOCK_SEQPACKETHOST = 'localhost' # windows: '127.0.0.1' / 'localhost'; linux:0.0.0.0
PORT = 10086def tcp_server():'''TCP服务端'''# 1. 实例化socket对象server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 可重用地址# 2. 绑定server.bind((HOST, PORT))  # 绑定# 3. 监听链接server.listen()while True:# 4. 接收一个连接conn, addr = server.accept()  # (阻塞等待)接收一个连接, 返回 连接对象 地址while True:# 5. 接收/发送数据 (接收数据(命令), 发送数据量, 接收反馈, 发送全部数据)data_bytes = conn.recv(1024)  # (阻塞)接收数据if not data_bytes:break  # 当client断开时,conn.recv不断的接收空信息data_str = data_bytes.decode("utf-8")print("接收到数据: {}".format(data_str))res_cmd_bytes = os.popen(data_str).read().encode("utf-8")if not res_cmd_bytes:res_cmd_bytes = b"success"conn.send(str(len(res_cmd_bytes)).encode("utf-8"))  # 不能发送空数据conn.recv(1024)  # 为避免粘包, 发送数据后接收下客户端的反馈conn.send(res_cmd_bytes)  # 每次发送的数据量与缓存有关# 6. 关闭连接, 释放资源conn.close()server.close()def tcp_client(data):'''TCP客户端:param data: 字符串数据'''# 1. 实例化对象client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 2. 连接服务端client.connect((HOST, PORT))  # 连接if not data:returndata_bytes = data.encode("utf-8")# 3. 发送/接收数据 (发送数据, 接收反馈, 发送反馈, 接收全部数据)client.send(data_bytes)  # 发送数据, 发送的数据不能为空, 未发完的数据将放到缓冲区继续发res_count_bytes = client.recv(1024)  # 接收数据, 每次接收的数据量有限制, 限制大小与系统有关client.send(b"seccess")  # 给服务器反馈if not res_count_bytes:res_count_bytes = b'0'res_count_int = int(res_count_bytes.decode("utf-8"))res_size_int = 0size = 1024  # 默认接收量res_data = b""while res_size_int < res_count_int:count_res_surplus = res_count_int - res_size_intif count_res_surplus <= size:size = count_res_surplusdata = client.recv(size)  # 接收剩余的数据res_size_int += len(data)res_data += dataelse:print("数据总量: {}".format(res_size_int))data_str = data.decode("utf-8")print("数据: {}".format(data_str))# 4. 关闭连接, 释放资源client.close()  # 关闭连接def udp_server():'''UDP服务端'''# 1. 实例化对象server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 可重用地址# 2. 绑定server.bind((HOST, PORT))while True:# 3. 接收数据data, address = server.recvfrom(1024)data_str = data.decode("utf-8")print("接收到数据: ", data_str)res_cmd_bytes = os.popen(data_str).read().encode("utf-8")if not res_cmd_bytes:res_cmd_bytes = b"success"if len(res_cmd_bytes) > 65507:res_cmd_bytes = res_cmd_bytes[:65507]server.sendto(res_cmd_bytes, address)  # 发送的数据限制为: 65535 - IP头(20) - UDP头(8) = 65507bite, 超过则异常# 4. 关闭连接, 释放资源server.close()def udp_client(data):'''UDP客户端:param data: 字符串数据'''# 1. 实例化对象client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)if not data:returndata_bytes = data.encode("utf-8")# 2. 发送/接收数据client.sendto(data_bytes, (HOST, PORT))res, addr = client.recvfrom(65507)print("接收到数据: ", res.decode("utf-8"))# 3. 关闭连接, 释放资源client.close()def socket_func():sk = socket.socket()# === socket ===sk.connect(('127.0.0.1', 8080))  # 连接sk.connect_ex(('127.0.0.1', 8080))  # 同connect, 返回错误提示符, 成功:0, 失败:errno变量值sk_temp = sk.dup()  # 复制套接字conn, addr = sk.accept()  # 阻塞式接收一个连接sk.bind(('127.0.0.1', 8080))  # 绑定# socket.listen([backlog]) // 监听连接, backlog限制未接受连接数, 默认合理值sk.listen()sk.getpeername()  # 远程套接字地址sk.getsockname()  # 自己套接字地址# socket.send(bytes[, flags]) // 发送数据(注:不许发送空数据) flags:与Unix系统有关,默认0sk.send(b"datas")# socket.sendall(bytes[, flags]) // 同sendsk.sendall(b"datas")# socket.sendfile(file, offset=0, count=None) // 发送文件, offset:从哪开始读, count:限制发送的总字节数sk.sendfile(open("file.txt", 'rb'))  # 实际发送的是文本里的内容# socket.sendto(bytes, address) // 发送数据, 未作远程套接字连接时使用# socket.sendto(bytes, flags, address)sk.sendto(b"datas", ('127.0.0.1', 8080))# socket.recv(bufsize[, flags]) // 接收数据, bufsize:限制接收数据量 (注:非设置1024就能接收到1024的数据量)bytes = sk.recv(1024)# socket.recvfrom(bufsize[, flags]) // 接收数据,返回 (bytes, addr)bytes, addr = sk.recvfrom(1024)sk.close()  # 关闭, 可用with自动关闭sk.shutdown(socket.SHUT_RD)  # 关闭连接(一半/两半) SHUT_RD:不许接收, SHUT_WR:不许发送, SHUT_RDWR:不许接收和发送fd = sk.detach()  # 置于关闭状态,返回文件描述符fd = sk.fileno()  # 获取文件描述符, 失败:-1sk.get_inheritable()  # Socket是否可继承# socket.makefile(mode='r', buffering=None, *, encoding=None, errors=None, newline=None) // 返回与套接字关联的文件对象file = sk.makefile()sk.setblocking(True)  # 设置是否为阻塞式套接字, False:无阻塞(sock.settimeout(0.0)), True:阻塞(sock.settimeout(None))num = sk.gettimeout()  # 获取超时时间, 单位秒, 未设置Nonesk.settimeout(None)  # 阻塞套接字超时时间, 单位秒,非负, None:阻塞式, >=0:非阻塞式# socket.setsockopt(level, optname, value) // 设置套接字属性的值sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)sk.family  # 地址簇sk.type  # 套接字类型sk.proto  # 套接字协议# === socket 异常 ===socket.error  # OSErrorsocket.herror  # 地址转换错误, gethostbyname_ex()socket.gaierror  # 地址错误, getaddrinfo()socket.timeout  # 超时异常# === socket 功能函数 ===# 创建# socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) // 创建新的套接字; family:地址簇, type:套接字类型, proto:协议号, fileno:文件描述符sk = socket.socket()# ---# socket.socketpair([family[, type[, proto]]]) // 创建一对已连接的socket对象sk = socket.socketpair()# socket.fromfd(fd, family, type, proto=0) // 从文件描述符fd, 创建一个套接字sk = socket.fromfd(sk.detach(), socket.AF_INET, socket.SOCK_STREAM)# 连接# ---# socket.create_connection(address[, timeout[, source_address]]) // 连接互联网上侦听的TCP地址  address:(host, port), timeout:超时, source_address:(host, port)socket.create_connection(('localhost', 12345))# 获取信息strs = socket.gethostname()  # 获取主机名num = socket.getdefaulttimeout()  # 默认超时时间, 没有Nonesocket.setdefaulttimeout(5)  # 设置默认超时时间, 单位秒# 转换strs = socket.gethostbyname('DESKTOP-S62UA6O')  # 将主机名转为ipv4地址host, hosts, ipaddrs = socket.gethostbyname_ex('DESKTOP-S62UA6O')  # 同gethostbynamehost, hosts, ipaddrs = socket.gethostbyaddr('192.168.1.103')  # 同gethostbyname# socket.getnameinfo(sockaddr, flags) 根据flags翻译sockaddr, flags: NI_DGRAM / NI_NAMEREQD / NI_NOFQDN / NI_NUMERICHOST / NI_NUMERICSERVhost, port = socket.getnameinfo(('192.168.1.103', 80), socket.NI_NUMERICHOST)# socket.getservbyname(servicename[, protocolname]) // 根据服务名获取端口号, protocolname: 'tcp' / 'udp'port = socket.getservbyname('http')# socket.getservbyport(port[, protocolname]) // 根据端口号获取服务名strs = socket.getservbyport(80)# socket.ntohl(x) // 将32位正整数从网络字节顺序转换为主机字节顺序# socket.ntohs(x) // 将16位正整数从网络转换为主机字节顺序# socket.htonl(x) // 将32位正整数从主机转换为网络字节顺序# socket.htons(x) // 将16位正整数从主机转换为网络字节顺序bytes_ip = socket.inet_aton('192.168.1.103')  # 将IPv4地址转换为32位二进制格式strs = socket.inet_ntoa(bytes_ip)  # 将32位二进制格式地址转为IPv4地址# socket.inet_pton(address_family, ip_string)bytes_ip = socket.inet_pton(socket.AF_INET, '192.168.1.103')  # 同inet_atonstrs = socket.inet_ntop(socket.AF_INET, bytes_ip)  # 同inet_ntoa# ---# socket.getaddrinfo(host, port, family=0, type=0, proto=0, flags=0) 将主机/端口转为创建套接字所需的所有参数(family, type, proto, canonname, sockaddr)lists = socket.getaddrinfo('luzhuo.me', 80, family=socket.AF_INET, type=socket.SOCK_STREAM)# socket.getfqdn([name]) // 名称的完全限定域名(主机名), 空为本机strs = socket.getfqdn('www.baidu.com')if __name__ == "__main__":# TCPtcp_server()while 1:data = input("输入数据: ")tcp_client(data)# UDPudp_server()while 1:data = input("输入数据: ")udp_client(data)# socket_func()

socketserver

#!/usr/bin/env python
# coding=utf-8
__author__ = 'Luzhuo'
__date__ = '2017/5/15'
# socketserver_demo.py 网络服务框架, 简化了socket的服务端编写, 是对socket的封装, 可进行多线程/多进程并发
# 客户端仍然使用socketimport socketserver# 具体服务器类
# socketserver.TCPServer  # TCP协议
# socketserver.UDPServer  # UDP协议
# socketserver.UnixStreamServer  # Unix TCP
# socketserver.UnixDatagramServer  # Unix UDP# 继承关系
# BaseServer
#     TCPServer
#         UnixStreamServer
#     UDPServer
#         UnixDatagramServer# 服务类(1. 要实现服务, 必须从BaseRequesthandler派生类, 并重新定义handle()方法)
# socketserver.ForkingMixIn  # 混合类的分叉版本
# socketserver.ThreadingMixIn  # 混合类的线程版本
# 以下类是min-in类预定义的
# socketserver.ForkingTCPServer  # 多进程 (Linux可用, Windows不可用)
# socketserver.ForkingUDPServer
# socketserver.ThreadingTCPServer  # 多线程
# socketserver.ThreadingUDPServerHOST, POST = "localhost", 10086# 所有请求处理对象的超类,他定义了接口
class TCPHandler(socketserver.BaseRequestHandler):def handle(self):# 一个连接调用一次handle()print(self.__dict__)# 与client的交互全都在这里完成while 1:try:data = self.request.recv(1024).strip()  # 接收数据ip = self.client_address[0]  # IPprint("IP: {}, 数据: {}".format(ip, data.decode('utf-8')))self.request.sendall(b"success")  # 发送数据except ConnectionResetError as e:  # 客户端断开print("客户端断开连接")breakdef setup(self):# handle()调用之前,所需的初始化操作passdef finish(self):# handle()调用之后,所需的清理操作, setup()异常不会调用该函数passclass UDPHandler(socketserver.BaseRequestHandler):def handle(self):data = self.request[0].strip()  # 接收数据socket = self.request[1]ip = self.client_address[0]  # IPprint("IP: {}, 数据: {}".format(ip, data.decode('utf-8')))socket.sendto(b"success", self.client_address)def socketserver_demo():'''1. 创建handler类,继承BaseRuestHandler,重写handler()2. 实例化server类(TCPServer), 传递ip和handler传给服务类3. server类.serve_forever()[处理多个请求] / .handler_request()[处理单个请求]4. server类.server_close() 关闭socket'''# TCP# server = socketserver.TCPServer((HOST, POST), ServerHandler)  # 单线程server = socketserver.ThreadingTCPServer((HOST, POST), TCPHandler)  # 多线程, 每次新的连接都会开启新线程# server.handle_request()  # 处理单个请求server.serve_forever()  # 处理多个请求# UDP# server = socketserver.UDPServer((HOST, POST), ServerHandler)  # 单线程server = socketserver.ThreadingUDPServer((HOST, POST), UDPHandler)  # 多线程, 每次新的连接都会开启新线程# server.handle_request()  # 处理单个请求server.serve_forever()  # 处理多个请求def socketserver_func():# 2. 创建服务类# class socketserver.BaseServer(server_address, RequestHandlerClass) // 所有服务类对象的超类, 他定义了接口server = socketserver.TCPServer((HOST, POST), TCPHandler)fd = server.fileno()  # 文件描述符server.handle_request()  # 处理单个请求, hanle()引发一场调用handle_error(), 超时调用handle_timeout()# serve_forever(poll_interval=0.5) // 处理多个请求,直到显式的shutdown()请求, 每poll_interval秒关闭pollserver.serve_forever()server.service_actions()  # 在serve_forever()循环中调用, 可用于清理数据server.shutdown()  # 告知serve_forever()停止并等待server.server_close()  # 清理服务器server.address_family  # 地址簇request = server.RequestHandlerClass  # 请求处理类, 为每个请求创建此类host, port = server.server_address  # 服务器正在侦听的地址socket = server.socket  # 套接字对象boolean = server.allow_reuse_address  # 服务器是否允许重用地址size = server.request_queue_size  # 请求队列的大小, 默认5个, 队列已满,下个请求将获得'连接被拒绝'错误type = server.socket_type  # 套接字类型time = server.timeout  # 超时时间, 单位秒, None:阻塞式, 0.0:非阻塞式# server.finish_request(request, client_address) // handle(self), self:{'request': ..., 'client_address': ..., 'server': ...}server.finish_request(request, (HOST, POST))  # handle()请求server.handle_error(request, (HOST, POST))  # handle()异常server.handle_timeout()  # handle()超时server.process_request(request, (HOST, POST))  # handle()请求, 如有必要创建新进程/线程处理请求boolean = server.verify_request(request, (HOST, POST))  # handle()是否可请求, True处理请求,False拒绝请求socket, addrs = server.get_request()  # 获取套接字请求(会阻塞,直至新的连接), 返回新套接字对象和客户端地址server.server_activate()  # 监听, 同listen()server.server_bind()  # 绑定if __name__ == "__main__":socketserver_demo()# socketserver_func()

这篇关于Python3 网络套接字(socket / socketserver)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/223975

相关文章

如何解决Druid线程池Cause:java.sql.SQLRecoverableException:IO错误:Socket read timed out的问题

《如何解决Druid线程池Cause:java.sql.SQLRecoverableException:IO错误:Socketreadtimedout的问题》:本文主要介绍解决Druid线程... 目录异常信息触发场景找到版本发布更新的说明从版本更新信息可以看到该默认逻辑已经去除总结异常信息触发场景复

python3 pip终端出现错误解决的方法详解

《python3pip终端出现错误解决的方法详解》这篇文章主要为大家详细介绍了python3pip如果在终端出现错误该如何解决,文中的示例方法讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下... 目录前言一、查看是否已安装pip二、查看是否添加至环境变量1.查看环境变量是http://www.cppcns

Linux网络配置之网桥和虚拟网络的配置指南

《Linux网络配置之网桥和虚拟网络的配置指南》这篇文章主要为大家详细介绍了Linux中配置网桥和虚拟网络的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 一、网桥的配置在linux系统中配置一个新的网桥主要涉及以下几个步骤:1.为yum仓库做准备,安装组件epel-re

python如何下载网络文件到本地指定文件夹

《python如何下载网络文件到本地指定文件夹》这篇文章主要为大家详细介绍了python如何实现下载网络文件到本地指定文件夹,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下...  在python中下载文件到本地指定文件夹可以通过以下步骤实现,使用requests库处理HTTP请求,并结合o

Linux高并发场景下的网络参数调优实战指南

《Linux高并发场景下的网络参数调优实战指南》在高并发网络服务场景中,Linux内核的默认网络参数往往无法满足需求,导致性能瓶颈、连接超时甚至服务崩溃,本文基于真实案例分析,从参数解读、问题诊断到优... 目录一、问题背景:当并发连接遇上性能瓶颈1.1 案例环境1.2 初始参数分析二、深度诊断:连接状态与

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

python3 gunicorn配置文件的用法解读

《python3gunicorn配置文件的用法解读》:本文主要介绍python3gunicorn配置文件的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python3 gunicorn配置文件配置文件服务启动、重启、关闭启动重启关闭总结python3 gun

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

SpringBoot使用OkHttp完成高效网络请求详解

《SpringBoot使用OkHttp完成高效网络请求详解》OkHttp是一个高效的HTTP客户端,支持同步和异步请求,且具备自动处理cookie、缓存和连接池等高级功能,下面我们来看看SpringB... 目录一、OkHttp 简介二、在 Spring Boot 中集成 OkHttp三、封装 OkHttp