python网络编程socket编程(TCP、UDP客户端服务器)
摘录 python核心编程
使用socket()模块函数创建套接字——通信端点
>>> from socket import *
>>> tcpSock = socket(AF_INET,SOCK_STREAM)
>>> udpSock = socket(AF_INET,SOCK_DGRAM)
其中,AF_INET表示使用的是IPv4协议,SOCK_STREAM表示的面向连接的TCP协议,SOCK_DGRAM表示面向无连接的UDP协议。
在创建TCP和UDP客户端与服务器前,先看看socket模块的属性以及套接字对象的方法
socket模块的属性:
| 属性名 | 描述 |
| 数据属性 | |
| AF_UNIX、AF_INET、AF_INET6、AF_NETLINK、AF_TIPC | python支持的套接字地址家族 |
| SO_STREAM、SO_DGRAM | 套接字类型(TCP=流,UDP=数据报) |
| has_ipv6 | 表示是否支持IPv6的布尔标志 |
| 异常 | |
| error | 套接字相关错误 |
| herror | 主机和地址相关错误 |
| gaierror | 地址相关错误 |
| timeout | 超时时间 |
| 函数 | |
| socket() | 以给定的地址家族、套接字类型和协议类型(可选)创建一个套接字对象 |
| socketpair() | 以给定的地址家族、套接字类型和协议类型(可选)创建一对套接字对象 |
| create_connection() | 常规函数,它接收一个地址(主机、端口号)对,返回套接字对象 |
| fromfd() | 以一个打开的文件描述符创建一个套接字对象 |
| ssl() | 通过套接字启动一个安全套接字连接,不执行证书验证 |
| getaddrinfo() | 获取一个五元组序列形式的地址信息 |
| getnameinfo() | 给定一个套接字地址,返回二元组(主机名、端口号) |
| getfqdn() | 返回完整的域名 |
| gethostname() | 返回当前主机名 |
| gethostbyname() | 将一个主机名映射到它的IP地址 |
| gethostbyname_ex() | gethostname()的扩展,返回主机名、别名主机集合和IP地址列表 |
| gethostbyaddr() | 将一个IP地址映射到DNS信息;返回和gethostbyname_ex()相同的三元组 |
| getprotobyname() | 将一个协议名映射到一个数字 |
| getservbyname()/getservbyport() | 将一个服务名映射到一个端口号,或者反过来;任何一个函数,协议名都是可选的 |
| ntohl()/ntohs() | 将来自网络的整数转换为主机字节顺序 |
| htonl()/htons() | 将来自主机的整数转换为网络字节顺序 |
| inet_aton()/inet_ntoa() | 将IP地址八进制字符串转换为32位包格式,或者反过来(仅用于IPv4地址) |
| inet_pton()/inet_ntop() | 将IP地址字符串转换为打包的二进制格式,或者反过来(适用于IPv4和IPv6) |
| getdefaulttimeout()/setdefaulttimeout() | 以秒为单位,获得/设置默认套接字超时时间 |
套接字对象方法和属性:
| 名称 | 描述 |
| 服务器套接字特有方法 | |
| s.bind() | 将地址(主机名、端口号)绑定到套接字上 |
| s.listen | 设置并启动TCP监听器 |
| s.accept() | 被动接受TCP客户端连接,一直等到直到连接到达(阻塞) |
| 客户端套接字特有方法 | |
| s.connect() | 主动发起TCP服务器链接 |
| s.connect_ex() | connect()的扩展,此时会以错误码的形式返回问题,而不是抛出一个异常 |
| 普通的套接字方法 | |
| s.recv() | 接受TCP消息 |
| s.recv_into() | 接受TCP消息到指定的缓冲区 |
| s.send() | 发送TCP消息 |
| s.sendall() | 完整的发送TCP消息 |
| s.recvfrom() | 接受UDP消息 |
| s.recvfrom_into() | 接受UDP消息到指定的缓冲区 |
| s.sendto() | 发送UDP消息 |
| s.getpeername() | 连接到套接字(TCP)的远程地址 |
| s.getsockname() | 当前套接字的地址 |
| s.getsockopt() | 返回给定套接字选项的值 |
| s.setsockopt() | 设置给定套接字选项的值 |
| s.shutdown() | 关闭连接 |
| s.close() | 关闭套接字 |
| s.detach() | 在未关闭文件描述符的情况下关闭套接字,返回文件描述符 |
| s.ioctl() | 控制套接字的模式(仅支持windows) |
| 面向阻塞的套接字方法 | |
| s.setblocking() | 设置套接字的阻塞或者非阻塞模式 |
| s.settimeout() | 设置阻塞套接字操作的超时时间 |
| s.gettimeout() | 获取阻塞套接字操作的超时时间 |
| 面像文件的套接字方法 | |
| s.fileno() | 套接字的文件描述符 |
| s.makefile() | 创建于套接字关联的文件对象 |
| 数据属性 | |
| s.family | 套接字家族 |
| s.type | 套接字类型 |
| s.proto | 套接字协议 |
创建TCP服务器
首先先来说说服务器设计的一般思路(伪代码):
ss = socket() #1、创建服务器套接字
ss.bind() #2、套接字于地址绑定
ss.listen() #3、监听连接
inf_loop: #4、服务器无限循环:
cs = ss.accept() #1)接收客户端连接
comm_loop: #2)通信循环
cs.recv()/cs.send() #①对话(接收/发送)
cs.close() #3)关闭客户端套接字
ss.close() #5、关闭服务器套接字(如有必要)
值得关心的是accept()的调用。该步骤默认会以阻塞的形式开启一个单线程服务器,用于等待客户端的连接,如果连接成功,则会返回一个独立的客户端套接字,用于和即将到来的消息进行交换,直到连接终止(终止方式一般是一方关闭连接或者向另外发送一个空字符串)。
下面的tsTserv.py脚本描述的是一个TCP服务器,接收来自客户端的消息,然后将消息加上时间戳前缀并发送给客户端:
#导入了time.time()和socket模块的所有属性
from socket import *
from time import ctime HOST = '' #空白的变量,表示可以使用任何可用的地址
PORT = 21567 #端口号
BUFSIZ = 1024 #缓冲区大小,单位是bite
ADDR = (HOST,PORT) tcpSerSock = socket(AF_INET,SOCK_STREAM) #创建一个TCP套接字
tcpSerSock.bind(ADDR) #绑定地址
tcpSerSock.listen(5) #启动TCP监听,其中5表示在连接被转接或拒绝之前,传入连接请求的最大数 while True: #服务器无限循环
print('服务器等待连接……')
tcpCliSock,addr = tcpSerSock.accept() #被动等待客户端的连接,当连接请求出现的时候,会返回一个新的套接字和客户端的地址组成的元组,于该客户端的通信是在这个新的套接字上进行数据的接受和发送s
print('……来自于:',addr) while True: #上述新套接字中进行通信循环
data = tcpCliSock.recv(BUFSIZ).decode('utf-8') #接受客户端发送过来的消息,从网络传输过来的是bytes类型的,需要解码
print(data)
if not data: #如果客户端发送的内容为空,认为客户端已经关闭,此时应该退出通信循环
break
tcpCliSock.send(('[%s] %s' % (ctime(),data)).encode('utf-8')) #服务器将处理的内容发送给客户端,需要将字符串类型数据转化为bytes数据。 tcpCliSock.close() #关闭当前客户端连接,下一步是等待另外一个客户端
tcpSerSock.close()
创建TCP客户端
下面给出创建客户端的伪代码:
cs = socket() #创建客户端套接字
cs.connect() #尝试连接服务器
comm_loop: #通信循环
cs.send()/cs.recv() #对话(发送/接收)
cs.close() #关闭客户端套接字
下面的tsTclnt.py脚本是和上面创建的服务器相关的客户端代码-连接服务器,并以逐行数据的形式提示用户,并展示从服务器返回的数据:
#导入socket模块的所有属性
from socket import * HOST = '192.168.1.125' #服务器的主机名,这里是在本地一台计算机上测试,所以这里是本地计算地址
PORT = 21567 #服务器的端口号,必须和服务端的端口号设置一样
BUFSIZ = 1024
ADDR = (HOST,PORT) tcpCliSock = socket(AF_INET,SOCK_STREAM) #创建客户端套接字
tcpCliSock.connect(ADDR) #主动调用并尝试连接服务器 while True: #无限循环
data = input('>') #等待客户端的录入
if not data: #如果用户没有输入任何的东西,则退出无限循环
break
tcpCliSock.send(data.encode('utf-8')) #将客户端的数据发送到服务器,并将字符串编码为bytes类型
data = tcpCliSock.recv(BUFSIZ).decode('utf-8') #接收服务器返回的数据
if not data: #如果服务器终止了或者上一步的recv()方法调用失败的话,也会退出无限循环
break
print(data) #正常情况下,从服务器返回的数据会被打印出来 tcpCliSock.close() #关闭客户端套接字
运行结果
首先,启动服务器
然后,在另外一台计算机(或者本机,记得更改对应的IP地址呦)上执行客户端脚本。然后就可以进行两台计算机的通信表演了。
这里要特别强调的是,我测试的版本是3.6x,通信端点发送接收内容的一定要进行编码和解码!因为,区别于2.x版本,在python3.x版本中,字符串和bytes是两种不同的数据类型了。
创建UDP服务器
和TCP服务器相比,UDP不需要那么多设置(因为他不是面向连接的),下面是伪代码:
ss = socket() #创建服务器套接字
ss.bind() #绑定服务器套接字
inf_loop: #服务器无限循环
cs = ss.recvfrom()/ss.sendto() #关闭(接收/发送)
ss.close() #关闭服务器套接字
上脚本:
#导入需要的模块
from socket import *
from time import ctime HOST = ''
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST,PORT) udpSerSock = socket(AF_INET,SOCK_DGRAM)
udpSerSock.bind(ADDR) #这里明显和TCP不同,没有所谓的‘监听传入的连接’的动作 while True:
print('等待接收消息……')
data,addr = udpSerSock.recvfrom(BUFSIZ) #接收数据报
udpSerSock.sendto(('时间:%s 地址:%s 内容:%s' % (ctime(),addr,data)).encode('utf-8'),addr) #给客户端返回数据
print('……接收并返回数据于:',addr) #服务器上打印记录信息 udpSerSock.close() #一般来说用不到,更优雅的方法是将无限循环放入一个try catch模块中,在捕捉异常或者finally中实现关闭套接字
创建UDP客户端
from socket import * HOST = 'localhost'
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST,PORT) udpCliSOcket = socket(AF_INET,SOCK_DGRAM) while True:
data = input('请输入:')
if not data:
break
udpCliSOcket.sendto(data.encode('utf-8'),ADDR)
data,ADDR = udpCliSOcket.recvfrom(BUFSIZ)
if not data:
break
print(data.decode('utf-8'),ADDR) udpCliSOcket.close()
看到:UDP和TCP客户端循环的方式基本一样,唯一的区别在于,事先不需要建立与UDP服务器的连接,只是简单的发送一条消息并等待服务器的回复。
python网络编程socket编程(TCP、UDP客户端服务器)的更多相关文章
- 网络编程—网络基础概览、socket,TCP/UDP协议
网络基础概览 socket概览 socket模块—TCP/UDP的实现 TCP/UDP总结 网络基础概览 osi七层协议各层主要的协议 # 物理层传输电信号1010101010 # 数据链路层,以太网 ...
- java网络编程socket\server\TCP笔记(转)
java网络编程socket\server\TCP笔记(转) 2012-12-14 08:30:04| 分类: Socket | 标签:java |举报|字号 订阅 1 TCP的开销 a ...
- 网络编程Socket之TCP之close/shutdown具体解释(续)
接着上一篇网络编程Socket之TCP之close/shutdown具体解释 如今我们看看对于不同情况的close的返回情况和可能遇到的一些问题: 1.默认操作的close 说明:我们已经知道writ ...
- python基础之socket编程 (转自林海峰老师)
python基础之socket编程 阅读目录 一 客户端/服务器架构 二 osi七层 三 socket层 四 socket是什么 五 套接字发展史及分类 六 套接字工作流程 七 基于TCP的套接字 ...
- Python 基础之socket编程(一)
Python 基础之socket编程(一) 可以进行通信玩儿了,感觉不错不错,网络通信就像打电话,我说一句你听一句之后,你再说一句,我听一句,就这样.....下去了.不扯淡了,来来来,看看今天都搞了点 ...
- Python 基础之socket编程(二)
Python 基础之socket编程(二) 昨天只是对socket编程做了简单的介绍,只是把socket通信的框架搭建起来,要对其中的功能进行进一步的扩充,就来看看今天的料哈! 一.基于tcp的套接字 ...
- Python开发——12.socket编程
一.OSI七层 1.物理层 物理层的主要功能是基于电气特性发送高低电压(高代表1,低代表0)形成电信号,使计算机完成组网以达到接入Internet的目的 2.数据链路层 数据链路层是用来定义电信号的分 ...
- Python 基础之socket编程(三)
python 基础之socket编程(三) 前面实现的基于socket通信只能实现什么呢?在tcp协议的通信中就是一个用户说一句,服务端给你回一句,你再给服务端说一句,服务端再给你回一句,就这样一直友 ...
- python网络编程(Socket、TCP、UDP)
Socket 是网络编程的一个抽象概念,通常我们用一个Socket表示 "打开了一个网络链接",而打开一个Socket 需要知道目标计算机的IP 地址和端口号,再指定协议类型即可. ...
随机推荐
- [Odoo12基础教程]之第一篇-创建Todo应用
声明: 本教程基于 Ruter 老师的 [Odoo基础教程系列] ,Ruter老师教程的链接地址为:Odoo基础教程系列 . 至于为什么已经有了Ruter老师的教程,还要自己再搬移一份呢?是基于一 ...
- 高德JS依赖分析工程及关键原理
一.背景 高德 App 进行 Bundle 化后,由于业务的复杂性,Bundle 的数量非常多.而这带来了一个新的问题——Bundle 之间的依赖关系错综复杂,需要进行管控,使 Bundle 之间的依 ...
- MySQL CRUD使用之小总结
总结一下最近碰到的一些关于MySQL CRUD方面的语句. 在使用pymysql的executemany方法时,需要注意的几个问题: 1.在写sql语句时,不管字段为什么类型,占位符统一使用%s,且不 ...
- 【Android - 自定义View】之View的工作过程简介
View的工作过程分为三个过程: View的measure过程: View的layout过程: View的draw过程. 我们知道,一个Activity就是一个窗口,这个窗口中包含一个Window.一 ...
- master节点的部署介绍和前置工作
目录 组件介绍 组件介绍 kubernetes master节点运行组件如下: kube-apiserver.kube-scheduler.kube-controller-manager.kube-n ...
- mysql那些事(1)手机号与座机号码如何存储
创建mysql数据表的时候,经常会遇到手机号码和座机号码数据的存储问题. 先说手机号码:很多人喜欢使用数字来进行存储,手机号不涉及到运算,并且有时候要带括号,加号之类的字符,有时候还要以0开头.所以, ...
- React - 组件:类组件
目录: 1. 类组件有自己的状态 2. 继承React.Component-会有生命周期和this 3. 内部需要一个render函数(类组件会默认调用render方法,但不会默认添加,需要手动填写r ...
- Python爬虫实战之爬取糗事百科段子
首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把,这次我们尝试一下用爬虫把他们抓取下来. 友情提示 糗事百科在前一段时间进行了改版,导致之前的代码没法用了,会导致无法输出和CPU占用过高的 ...
- eclipse maven 项目导出为 jar 包
一个 maven 项目有很多依赖,所以最后打出的 jar 一般会很多,且比较大,打成 jar 包的步骤 (注意pom.xml文件中打包类型不能是war包): 1. 把 pom.xml 中依赖的库打成 ...
- play-with-docker搭配ffsend完成文件上传及下载(解决从docker hub拉取镜像慢问题)
由于众所周知的原因,大家有的时候pull docker hub上的镜像是很困难的,下载到99%就这么不动了也是很正常的事情 这个时候以下步骤是100%可以解决问题的: 1.找一台国外的服务器安装doc ...