Dave Python 练习十八 -- 网络编程
2011-09-19 11:10
316 查看
#encoding=utf-8 ###*************** 网络编程 *************** #********** Part 1: 套接字:通讯端点 ******************* ### 1.1 套接字 #套接字起源于20 世纪70 年代加利福尼亚大学伯克利分校版本的Unix,即人们所说的BSD Unix。 #因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 #一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或IPC。套接字有两种,分别是基于文 #件型的和基于网络型的。 #Unix 套接字是我们要介绍的第一个套接字家族。其“家族名”为AF_UNIX(在POSIX1.g 标准中 #也叫AF_LOCAL),表示“地址家族:UNIX”。包括Python 在内的大多数流行平台上都使用术语“地址 #家族”及其缩写“AF”。而老一点的系统中,地址家族被称为“域”或“协议家族”,并使用缩写“PF” #而不是“AF”。同样的,AF_LOCAL(在2000-2001 年被列为标准)将会代替AF_UNIX。不过,为了向后 #兼容,很多系统上,两者是等价的。Python 自己则仍然使用AF_UNIX。 #另一种套接字是基于网络的,它有自己的家族名字:AF_INET,或叫“地址家族:Internet”。 #还有一种地址家族AF_INET6 被用于网际协议第6 版(IPv6)寻址上。还有一些其它的地址家族,所有地址家族中,AF_INET 是使用最广泛的一个。 # #Python 2.5 中加入了一种Linux 套接字的支持:AF_NETLINK套接字家族让用户代码与内核代码之间的IPC 可以使用标准BSD 套 #接字接口。而且,相对之前那些往操作系统中加入新的系统调用,proc 文件系统支持或是“IOCTL”等笨重的方案来说,这种方法显得更为优美,更为安全。 # #Python 只支持AF_UNIX,AF_NETLINK,和AF_INET 家族。 ## 1.2 套接字地址:主机与端口 #如果把套接字比做电话的插口——即通讯的最底层结构,那主机与端口就像区号与电话号码的 #一对组合。有了能打电话的硬件还不够,你还要知道你要打给谁,往哪打。一个Internet 地址由网 #络通讯所必需的主机与端口组成。而且不用说,另一端一定要有人在听才可以。否则,你就会听到 #熟悉的声音“对不起,您拨的是空号,请查对后再播”。你在上网的时候,可能也见过类似的情况, #如“不能连接该服务器。服务器无响应或不可达”。 #合法的端口号范围为0 到65535。其中,小于1024 的端口号为系统保留端口。如果你所使用的 #是Unix 操作系统,保留的端口号(及其对应的服务/协议和套接字类型)可以通过/etc/services #文件获得。 ## 1.3 面向连接与无连接 ##1.3.1 面向连接 #无论你使用哪一种地址家族。套接字的类型只有两种。一种是面向连接的套接字,即在通讯之 #前一定要建立一条连接,就像跟朋友打电话时那样。这种通讯方式也被称为“虚电路”或“流套接 #字”。面向连接的通讯方式提供了顺序的,可靠的,不会重复的数据传输,而且也不会被加上数据边 #界。这也意味着,每一个要发送的信息,可能会被拆分成多份,每一份都会不多不少地正确到达目 #的地。然后被重新按顺序拼装起来,传给正在等待的应用程序。 #实现这种连接的主要协议就是传输控制协议(即TCP)。要创建TCP 套接字就得在创建的时候, #指定套接字类型为SOCK_STREAM。TCP 套接字采用SOCK_STREAM 这个名字,表达了它做为流套接字的 #特点。由于这些套接字使用Internet 协议(IP)来查找网络中的主机,这样形成的整个系统,一般 #会由这两个协议(TCP 和IP)来提及,即TCP/IP。 ## 1.3.2 无连接 #与虚电路完全相反的是数据报型的无连接套接字。这意味着,无需建立连接就可以进行通讯。 #但这时,数据到达的顺序,可靠性及数据不重复性就无法保证了。数据报会保留数据边界,这就表 #示,数据不会像面向连接的协议那样被拆分成小块。 #使用数据报来传输数据就像邮政服务一样。邮件和包裹不一定会按它们发送的顺序到达。事实 #上,它们还有可能根本到不了!而且,由于网络的复杂性,数据还可能被重复传送。 #既然数据报有这么多缺点,为什么还要使用它呢?由于 #面向连接套接字要提供一些保证,以及要维持虚电路连接,这都是很重的额外负担。数据报没有这 #些负担,所以它更“便宜”。通常能提供更好的性能,更适合某些应用场合。 #实现这种连接的主要协议就是用户数据报协议(即UDP)。要创建UDP 套接字就得在创建的时候, #指定套接字类型为SOCK_DGRAM。SOCK_DGRAM 这个名字,也许你已经猜到了,来自于单词“datagram” #(“数据报”)。由于这些套接字使用Internet 协议来查找网络中的主机,这样形成的整个系统,一 #般会由这两个协议(UDP 和IP)来提及,即UDP/IP。 #********** Part 2: Python 中的网络编程 ******************* ## 2.1 socket()模块函数 #要使用socket.socket()函数来创建套接字。其语法如下: #socket(socket_family, socket_type, protocol=0) #socket_family 可以是AF_UNIX 或AF_INET。socket_type 可以是SOCK_STREAM 或SOCK_DGRAM。 #这几个常量的意义可以参考之前的解释。protocol 一般不填,默认值为0。 #创建一个TCP/IP 的套接字,你要这样调用socket.socket(): #tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # #同样地,创建一个UDP/IP 的套接字,你要这样: #udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # #由于socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 #'from socket import *',我们就把socket 模块里的所有属性都带到我们的命名空间里了,这样能 #大幅减短我们的代码。 #tcpSock = socket(AF_INET, SOCK_STREAM) #当我们创建了套接字对象后,所有的交互都将通过对该套接字对象的方法调用进行。 ##2.2 套接字对象(内建)方法 #套接字对象的常用函数 #函数 描述 ####服务器端套接字函数 #s.bind() 绑定地址(主机,端口号对)到套接字 #s.listen() 开始TCP 监听 #s.accept() 被动接受TCP 客户的连接,(阻塞式)等待连接的到来 # ####客户端套接字函数 #s.connect() 主动初始化TCP 服务器连接 #s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛异常 # #####公共用途的套接字函数 #s.recv() 接收TCP 数据 #s.send() 发送TCP 数据 #s.sendall() 完整发送TCP 数据 #s.recvfrom() 接收UDP 数据 #s.sendto() 发送UDP 数据 #s.getpeername() 连接到当前套接字的远端的地址 #s.getsockname() 当前套接字的地址 #s.getsockopt() 返回指定套接字的参数 #s.setsockopt() 设置指定套接字的参数 #s.close() 关闭套接字 ####Blocking-Oriented Socket Methods #s.setblocking() 设置套接字的阻塞与非阻塞模式 #s.settimeout() 设置阻塞套接字操作的超时时间 #s.gettimeout() 得到阻塞套接字操作的超时时间 # ####面向文件的套接字的函数 #s.fileno() 套接字的文件描述符 #s.makefile() 创建一个与该套接字关连的文件 #2.3 创建一个TCP 服务器 #伪代码: #ss = socket() # 创建服务器套接字 #ss.bind() # 把地址绑定到套接字上 #ss.listen() # 监听连接 #inf_loop: # 服务器无限循环 #cs = ss.accept() # 接受客户的连接 #comm_loop: # 通讯循环 #cs.recv()/cs.send() # 对话(接收与发送) #cs.close() # 关闭客户套接字 #ss.close() # 关闭服务器套接字(可选) #所有的套接字都用socket.socket()函数来创建。服务器需要“坐在某个端口上”等待请求。所 #以它们必需要“绑定”到一个本地的地址上。由于TCP 是一个面向连接的通讯系统,在TCP 服务器 #可以开始工作之前,要先完成一些设置。TCP 服务器必需要“监听”(进来的)连接,设置完成之后, #服务器就可以进入无限循环了。 # #一个简单的(单线程的)服务器会调用accept()函数等待连接的到来。默认情况下,accept() #函数是阻塞式的,即程序在连接到来之前会处于挂起状态。套接字也支持非阻塞模式。 # #一旦接收到一个连接,accept()函数就会返回一个单独的客户的套接字用于后续的通讯。 #在临时套接字创建好之后,通讯就可以开始了。客户与服务器都使用这个新创建的套接字进行 #数据的发送与接收,直到通讯的某一方关闭了连接或发送了一个空字符串之后,通讯就结束了。 #在代码中,当客户连接关闭后,服务器继续等待下一个客户的连接。代码的最后一行,会把服 #务器的套接字关闭。由于服务器处在无限循环中,不可能会走到这一步,所以,这一步是可选的。 #我们写这一句话的主要目的是要提醒读者,在设计一个更智能的退出方案的时候,比方说,服务器 #被通知要关闭的时,要确保close()函数会被调用。 #示例:tsTserv.py 创建一个TCP 服务器程序,当客户端连接上来之后返回'hello dave' #encoding=utf-8 #from socket import * #from time import ctime # #HOST = '' #HOST 变量为空,表示bind()函数可以绑定在所有有效的地址上。 #PORT = 21567 #BUFSIZ = 1024 #缓冲的大小设定为1K #ADDR = (HOST, PORT) # #tcpSerSock = socket(AF_INET, SOCK_STREAM) #tcpSerSock.bind(ADDR) #tcpSerSock.listen(5) #最多允许多少个连接同时连进来,后来的连接就会被拒绝掉。 # #while True: # print('waiting for connection...') # tcpCliSock, addr = tcpSerSock.accept() # print('...connected from:', addr) # # while True: # data = tcpCliSock.recv(BUFSIZ) # if not data: # break # tcpCliSock.send(b'Hello Dave') #注意在Python 3.x 版本这里只能send bytes类型 # #tcpCliSock.close() #tcpSerSock.close() ## 2.4 创建TCP 客户端 #伪代码: #cs = socket() # 创建客户套接字 #cs.connect() # 尝试连接服务器 #comm_loop: # 通讯循环 #cs.send()/cs.recv() # 对话(发送/接收) #cs.close() # 关闭客户套接字 #所有的套接字都由socket.socket()函数创建。在客户有了套接字之后,马上就可 #以调用connect()函数去连接服务器。连接建立后,就可以与服务器开始对话了。在对话结束后,客户就可以关闭套接字,结束连接。 #tcTlnt.py 的代码。程序连接到服务器,向服务器发送‘hello world’,服务器返回‘hello dave’ #from socket import * # #HOST = 'localhost' #服务器的主机名与端口号 #PORT = 21567 #端口号要与服务器上的设置完全相同 #BUFSIZ = 1024 #ADDR = (HOST, PORT) # #tcpCliSock = socket(AF_INET, SOCK_STREAM) #tcpCliSock.connect(ADDR) # #while True: # tcpCliSock.send(b'Hello world') # data = tcpCliSock.recv(BUFSIZ) # # if not data: # break # print(data) # #tcpCliSock.close() ## 2.6 创建一个UDP 服务器 #由于UDP 服务器不是面向连接的,所以不用像TCP 服务器那样做那么多设置工作。事实上,并不用设置什么东西,直接等待进来的连接就好了。 #ss = socket() # 创建一个服务器套接字 #ss.bind() # 绑定服务器套接字 #inf_loop: # 服务器无限循环 #cs = ss.recvfrom()/ss.sendto() # 对话(接收与发送) #ss.close() # 关闭服务器套接字 # #从伪代码中可以看出,使用的还是那套先创建套接字然后绑定到本地地址(主机/端口对)的方法。 #无限循环中包含了从客户那接收消息,返回加了时间戳的结果和回去等下一个消息这三步。 #同样的,由于代码不会跳出无限循环,所以,close()函数调用是可选的。我们写这一句话的原因是 #要提醒读者,在设计一个更智能的退出方案的时候,要确保close()函数会被调用。 ##UDP 时间戳服务器 (tsUserv.py) #from socket import * #from time import ctime # #HOST = '' #PORT = 21567 #BUFSIZ = 1024 #ADDR = (HOST, PORT) # #udpSerSock = socket(AF_INET, SOCK_DGRAM) #udpSerSock.bind(ADDR) # #while True: # print('waiting for message...') # data, addr = udpSerSock.recvfrom(BUFSIZ) # udpSerSock.sendto(ctime().encode('utf-8'), addr) #这里注意在Python 3里sendto 需要用bytes 进行传送,所以需要使用encode进行转换 # print('...received from and returned to:', addr) # #udpSerSock.close() ## 2.7 创建一个UDP 客户端 #伪代码如下: #cs = socket() # 创建客户套接字 #comm_loop: # 通讯循环 #cs.sendto()/cs.recvfrom() # 对话(发送/接收) #cs.close() # 关闭客户套接字 ## UDP 客户端,程序会提示用户输入要传给服务器的信息,显示服务器返回的加了时间戳的结果。 #from socket import * # #HOST = 'localhost' #PORT = 21567 #BUFSIZ = 1024 #ADDR = (HOST, PORT) # #udpCliSock = socket(AF_INET, SOCK_DGRAM) # #while True: # data = input('> ') # if not data: # break # udpCliSock.sendto(data.encode('utf-8'), ADDR) #这里注意在Python 3里sendto 需要用bytes 进行传送,所以需要使用encode进行转换 # data, ADDR = udpCliSock.recvfrom(BUFSIZ) # if not data: # break # print(data) # #udpCliSock.close() #先运行服务器,在运行客户端,提示输入data,然后服务器返回时间。 ## 2.8 套接字模块属性 #socket 模块属性 # #属性名字 描述 # ####数据属性 #AF_UNIX, AF_INET, AF_INET6 Python 支持的套接字家族 #SO_STREAM, SO_DGRAM 套接字类型 (TCP = 流, UDP = 数据报) #has_ipv6 表示是否支持IPv6 的标志变量 # ####异常 #error 套接字相关错误 #herrora 主机和地址相关的错误 #gaierror 地址相关的错误 #timeout 超时 # ####函数 #socket() 用指定的地址家族,套接字类型和协议类型(可选)创建一个套接字对象 #socketpair() 用指定的地址家族,套接字类型和协议类型(可选)创建一对套接字对象 #fromfd() 用一个已经打开的文件描述符创建一个套接字对象 # ####数据属性 #ssl() 在套接字初始化一个安全套接字层(SSL)。不做证书验证。 #getaddrinfo() 得到地址信息 #getfqdn() 返回完整的域的名字 #gethostname() 得到当前主机名 #gethostbyname() 由主机名得到对应的ip 地址 #gethostbyname_ex() gethostbyname()的扩展版本,返回主机名,主机所有的别名和IP 地址列表。 #gethostbyaddr() 由IP 地址得到DNS 信息,返回一个类似gethostbyname_ex()的3 元组。 #getprotobyname() 由协议名(如'tcp')得到对应的号码。 #getservbyname()/ 由服务名得到对应的端口号或相反 #getservbyport() 两个函数中,协议名都是可选的。 #ntohl()/ntohs() 把一个整数由网络字节序转为主机字节序 #htonl()/htons() 把一个整数由主机字节序转为网络字节序 #inet_aton()/ 把IP 地址转为32 位整型,以及反向函数。(仅对IPv4 地址有效) #inet_ntoa() #inet_pton()/ 把IP 地址转为二进制格式以及反向函数。(仅对IPv4 地址有效) #inet_ntop() #getdefaulttimeout()/ 得到/设置默认的套接字超时时间,单位秒(浮点数) #setdefaulttimeout()
-------------------------------------------------------------------------------------------------------
Blog: http://blog.csdn.net/tianlesoftware Weibo: http://weibo.com/tianlesoftware Email: dvd.dba@gmail.com
DBA1 群:62697716(满); DBA2 群:62697977(满) DBA3 群:62697850(满)
DBA 超级群:63306533(满); DBA4 群: 83829929(满) DBA5群: 142216823(满)
DBA6 群:158654907(满) DBA7 群:69087192(满) DBA8 群:172855474
DBA 超级群2:151508914 DBA9群:102954821 聊天 群:40132017(满)
--加群需要在备注说明Oracle表空间和数据文件的关系,否则拒绝申请
相关文章推荐
- Dave Python 练习十八 -- 网络编程
- Dave Python 练习十八 -- 网络编程
- Dave Python 练习十八 -- 网络编程
- Dave Python 练习十八 -- 网络编程
- Dave Python 练习十九 -- 网络客户端编程
- Dave Python 练习十九 -- 网络客户端编程
- Dave Python 练习十九 -- 网络客户端编程
- Dave Python 练习十九 -- 网络客户端编程
- Dave Python 练习十九 -- 网络客户端编程
- PYTHON黑帽编程1.5 使用WIRESHARK练习网络协议分析
- python网络编程:socket、服务端、客户端
- Linux网络编程 - TCP Socket 简单练习:新进程辅助通信
- Dave Python 练习十四 -- 模块
- JavaSE_网络编程_TCP_练习3_图片
- Python3之网络编程总结
- python 网络编程
- Python之网络编程
- Python网络编程:E-mail服务(九) 发送HTML格式邮件
- python 网络编程
- python之高性能网络编程并发框架eventlet实例 推荐