python

Python 程序员都uhui熟悉文件 对象的方法: readline()、write()、read()等。Python库支持文件和文件类对象。 Socket对象不提供类似的接口,您或许会觉得这样不是很方便。然而Python的确提供过了一个makefile()函数来生成供您使用的文件类对象。


import socket, sys

port = 70
host = sys.argv[1]
filename = sys.argv[2]

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
fd = s.makefile('rw', 0)

fd.write(filename + "\r\n")

for line in fd.readline():
        sys.stdout.write(line)

~                                                                               
~                                     

这个程序大部分和前面版本一样。不同之处: 第一处是对makefile函数的调用。这个函数有两个可选参数: 操作文件类的模式和缓存(buffering)的模式。操作文件类的模式表示您是只读、止血或是既读又写;在本例中,程序需要既读又写,所以是'rw'。缓存主要用在磁盘文件,但是对于交互式的网络程序,它可能会阻碍程序的运行,所以最好通过设置为0来关上它。

 

既然能得到文件类对象,您就可以用熟悉的方法了。这里提供了两个: write() 和 readline() 他们的功能和一般的文件对象是一样的。


第一个Python客户端程序只用了20行左右的代码。用Python编写服务器程序同样也很简单,例如:

import socket

host = ''
port = 51423

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host, port))
s.listen(1)

print "Server is running on port %d; press Ctrl-C to terminate." % port

while 1:
        clientsock, clientaddr = s.accept()
        clientfile = clientsock.makefile('rw', 0)
        clientfile.write("Welcom," + str(clientaddr) + "\n")
        clientfile.write("Please enter a string: ")
        line = clientfile.readline().strip()
        clientfile.write("You entered %d charecters.\n" % len(line))
        clientfile.close()
        clientsock.close()
~                             


您可以运行一下例子看看。首先需要运行服务器程序。请把这个例子存为server.py ,接着运行一个如 run server.py 的命令,然后请打开一个终端或telnet应用程序并连接localhost的54123端口。您也许会发现,我根本没有编写Telnet协议,但是telnet客户端也能通信。可是尽管这个基本服务器程序可以运行,但它没有什么用处。



高级接口

尽管您看到的粒子介绍了如何用Python编写自己的协议, 您也许会京城使用一些普通的协议, 如HTTP或IMAP,而您可能不需要编写这么底层的网络程序,Python提供了很多协议模块, 他们可以很大程度上简化您的变成任务。 例如,不用自己编写代码来解析和理解HTTP header ,Python中的httplib模块会替您完成这个工作。事实上,在您开始变成的时候,有一半的工作已经完成了。


为了处理URL, Python提供的模块可以让您的代码和几种协议一起工作,这里有个例子:

import urllib, sys
host = sys.argv[1]
file = sys.argv[2]

f=urllib.urlopen('gopher://%s%s' % (host, file))
for line in f.readlines():
        sys.stdout.write(line)

~                                   
这个例子使用命令行参数组成一个URL, 并传给urllib。 仅仅bain写几行代码,您就可以使用urllib来实现多种文件下载程序。请试一试一下代码:

import urllib, sys

f = urllib.urlopen(sys.argv[1])
while 1:
        buf = f.read(2048)
        if not len(buf):
                break
        sys.stdout.write(buf)
~                                                                               
~                     

现在您可以把这个例子存为download.py, 并运行 run download.py http://baidu.com

这个命令可以解开数据并发送,您看到了,这只编写了11行代码。


总结: TCP/IP协议可以用于多种不同的传输,例如: modems连接的网络和以太网。每一个终端是靠唯一的IP地址和端口号来区分的。


服务器通过一些实现知道的端口来侦听连接。当一个客户端连接时,它的操作系统通常会选择一个事先不知道的端口号。


有两种常用的数据传输协议: TCP,可以提供高可靠性和完整的绘画: UDP,用于小且简短但是快速的会话。


大多数人用Python写网络程序,要么自己设计协议,要么用一些内置的模块来实现一些已经存在的协议。对那些自己设计协议的人来说,Python提供了全面的Socket接口.


当您编写网络服务的程序时,您会发现经常要写网络客户端程序。在本章中,您将学会如何在客户端实现一个应用程序协议。如果Python没有一个可以实现您想要的协议的模块,或者您想修改或扩展一个已经存在的Python模块的时候,则下面非常有用。


socket 是操作系统中I/O系统的延伸部分,它可以使进程和机器之间的通信成为可能。如果想完全理解SOCKET在当前系统上是如何工作的,熟悉一下它的历史是非常有用的。


当前经常使用的socket,最早起源于BSD unix 类的操作系统。在UNIXT系统上,比如BSD, 有一些现有的、和文件描述符一起工作的系统调用,其中包括open()、read()、write()和close()。 文件描述符一般是指一个文件或某个类似文件的实体。


把对网络的支持加入操作系统,是以一种扩展现有文件描述符结构的方法来实现的。新的系统调用并和socket一起工作,而很多现有的系统调用同样能和socket一起工作。因此一个socket允许您使用标准的操作系统和其他的计算机,以及您自己机器上的不同进程来通信。


在某些方面,socket可以被看成一个标准的文件描述符。在UNIXT类的平台上, read() write() DUP() DUP(),close()这样的系统调用会像为标准文件描述符那样为socket工作。很多时候,程序并不需要知道他正把数据写进一个文件、终端或是一个TCP连接。


然而, socket的确存在一些不同的工作方式。最明显的就是建立socket的方法。很多文件是通过调用open()函数来打开的, 但socket是通过调用socket()函数建立的,并且还需要另外的调用来连接和激活他们。 recv() 和 send()这两个系统调用和 read() 和 write()极为相似。send()和RECV() 调用提供了socket额外特有的功能。


Python通过SOCKET模块提供访问操作系统socket库的接口。建立SOCKET的时候,您只需调用这个模块的函数和常量。


1. 建立socket

对于一个客户端程序来说,建立一个socket需要两个步骤。首先,您需要建立一个实际的socket对象。其次,您需要把它连接到远程服务器上。


在建立socket对象的时候,您需要告诉系统两件事情:通信类型和协议家族。 通信类型指用什么协议来传输数据。协议的例子包括IPV4,IPV. 到目前位置,最常用的是IPV4, 写以家族则定义数据如何被传输。


大部分讲的是internet通信,对于它来说,通信类型基本上都是AF_INET。协议家族一般是表示TCP通信的SOCK_STREAM或表示UDP通信的SOCK_DGRAM。对于TCP通信,建立一个SOCKET连接,一般用类似这样的代码:

S = socket. socket(socket.AF_INET, socket。SOCK_STREAM)


连接socket, 您一般需要提哦给你个一个tuple,它包含远程主机名或IP地址和远程端口。连接一个SOCKET一般用类似这样的代码:


s.connect((“www.example.com”),80)


下面的程序建立一个连接并马上终止。它虽然不是很有用,但却是一个具有完整功能的例子,代码如下:




一旦建立了一个socket连接,您就可以从它那里得到一些有用的信息。




利用SOCKET通信


现在和socket的通信已经建立起来了,是利用它发送和接受数据的时候了。Python提供了两种方法: socket对象和 文件类对象。

socket对象提供了操作系统的send()、sendto()、recv() 和recvfrom() 调用的接口。文件类对象提供给了read()、wrte()、radline()这些更典型的python接口。


当您有一些特殊需求的时候socket对象特别有用。例如:读写数据时、您需要协议可以详细地控制时、使用二进制协议传送固定大小数据时、数据超时需要特殊处理时;在或者是任何不止需要简单读写时。当您编写UDP程序时,socket对象昂同样是很好的选择。



文件类对象一般用于面向线性的协议,因为它能够通过提供的readline()函数自动地为您处理大多数解析。然而,文件类对象一般只对TCP连接工作地和那后,对UDP连接反而不是很好。这是因为TCP连接的行为更像是标准的文件,他们保证数据接收的准确性,并且和文件一样是以字节流形式运转的。而UDP并不像文件那样以字节流形式运转。相反,它是一种基于信息报的通信。文件泪对象没有办法操作每个基本的信息包,因而建立、发送和接收UDP信息包的基本机制是不能工作的,并且错误检查也是非常困难的。



socket异常:

   不同的网络调用会产生不同的异常。下面的例子掩饰了当处理socket对象时,如何捕获每一个普通的异常。这个例子需要3个命令行参数:一个是想要连接的主机名,一个是服务器上的端口号或名字,一个是想从五夫妻请求的为念。程序将连接上服务器,针对所请求文件的名字发送一个简单的HTTP请求,显示结果。在整个过程中,它将尝试处理各种类型潜在的错误。






学习了如何编写网络客户端,建立一个socket,连接到一个服务器,接着和服务器通信。

开始学习如何写网络服务器。服务器的特点是等待来自客户端的请求,发送应答。通常来说,服务器可以做任何事情,从分发WEB页面到交换E-mail。

在某些方面,服务器程序和客户端程序很类似。很多您熟悉的用在网络客户端程序的指令同样可以用在服务器程序中,因为服务器使用的是和客户端同样的socket接口。


但是,还是有一些重要的细节是不同的,最明显的是建立socket。同样的额,还有一些问题需要考虑,那就是在客户端频发发出的突发事件。将要学习如何从头建立一个服务器程序、如何获取客户端信息、如何把活动记入日志,以及如何用不同的方式来运行您的服务器。


对于客户端来说,建立一个TCP连接的过程分为两步,包括建立socket对象以及调用conect()来简历一个和服务器的连接。


对于服务器,这个过程需要如下四步:

1.建立socket对象。

2.设置socket选项。

3.绑定到一个端口(同样,也可以是指定的网卡)

4.侦听连接。




对于一个服务器管理员来说,通信状态的一个重要内容是记录日志文件。UNIX和类Unix系统提供了一个成为syslog的工具,它可以帮助您,而且Python为它提供了一个很方便的接口。



一个经常困扰服务器设计者的问题是死锁。死锁发生在当一个服务器和客户端同时试图往一个连接上写或读的时候。在这些情况下,没有进程可以得到任何数据。因此,如果他们正在写,向外的buffer会被充满,结果他们就好像是被骗了,什么都做不了。



总结: 服务器主要是等待来自客户端的请求并发送响应。和客户端程序一样,服务器也使用socket接口,但是建立一个socket的过程多达四步。

socket选项可以用来对一个特殊的连接而改变网络系统的行为。对服务器来说,最常用的选项是SO_REUSERDDR, 它允许端口在socket关闭之后,马上就被重新使用。


TCP和UDP的服务器都是颗星的。TCP服务器一般会用ACCEPT()来为每个链接的客户端建立一个新的sockt。UDP服务器一般只是使用一个单一的socket, 并完全依靠从recvfrom()返回的值来判断该往哪里发送响应。


inetd和xinetd程序提供了一个方便的方法来侦听连接并把他们转给服务器处理。二者的用途是一样的,尽管她们的配置是不同的。通过inetd或xinetdl来工作的服务器会默认地把他们的标准输入和输出设置为socket.


因为服务器程序几乎不是交互地运行的,您需要找到一个方法可以和操作员交换信息。UNIX系统提供syslog接口,而PYTHON也有一个相关的模块。


当服务器和客户端都停下来等候一个行为出现的时候,有可能会发生死锁。小心的设计协议并适当地使用超时,可以把死锁出现的频率和影响减至最小。




域名系统(DNS) 是一个分布式的数据库,它主要用来把主机名转换成IP地址。


DNS是一个庞大的、全球的分布式数据库。它提供一系列的提名问答,每一个提名给出一个更详细的答案,直到获得最终答案。


作为一个例子,让我们来查询一下www.external.example.com.首先,您的程序会和操作系统配置文件指定的本地名称服务器通信。这个服务器是一个递归的名称服务器,它收到的请求并以适当的方式传递下去。他会为您完成大量工作。

递归服务器做的第一件事就是询问.com域。后者有个内置的顶级域名列表,这些服务器可以分发世界上顶级域名的信息,例如.com.

对于.com的回答是以一种指向另一个名称服务器的提名形式给出的。这个名称服务器可以提供名称中包含.com的信息。所以查询会发送到这个服务器。


这个循环重复多次,知道最终查询到达为external.example.com服务的名称服务器,这个服务器知道问题中的IP地址,并返回它。


操作系统提供执行基本DNS查找的服务。这些服务队大多数程序员来说是足够的,直接节约了您花费在处理各种DNS查询上的时间。Pytho在它的socket模块中,提供了访问这些基本操作系统服务的接口。






高级网络操作:


Python对于TCP\IP网络的支持,为不通过类型的程序提供了很多有用的特性。他们大多既适用于客户端,也适用于服务器。


在网络上传输数据有一个很普遍的问题,那就是传输不确定长度的字符串。当您从TCP信息流上读取信息的时候,除非在协议中您加入了某种指示标志,否则您不知道什么时候数据发送结束。

有两种方法可以解决这个问题:一个唯一的字符串结束标识符和一个在开始部分的固定长度字符串大小的指示器。




理解网络字节顺序:

当您在网络上发送






Web客户端访问

Internet一个重要的技术的用途之一就是WWW,这也意味着它的主要协议——超文本传输协议(HTTP)是大多数程序员必须用到的。很自然python为编写Web和HTTP客户端提供了大量的模块。


urllib2模块,实际上为实现不同协议的多个模块提供了一个通用的接口,其中HTTP显然是urllib2中最常用的协议。


使用urllib2:

下载web页面

在远程http服务器上验证

提交表单数据

处理错误

与非http协议通信



获取web页面:

从一个远端服务器上下载一个WEB页面经常是需要的,。例如:为了在某个应用程序中显示天气情况,您就需要下载一个天气数据 页面。或者,您想为某个旅游计划应用程序下载一个航班日程。


下面是要给简单的例子,它使用命令行指定的url,在取得页面后放到标准输出中。


您可以运行这个程序并看到组成Web页面的HTML代码。



您可以看到,这是一段非常简单的程序,它可以和urllib2支持的任何协议工作——不仅仅是HTTP,还包括FTP和gopher. 通常,第一件事情是要建立urllib2.Request对象。该对象用URL做参数,您也可以在打开链接之前,设置其他参数。当调用urlopen()的时候,对象被传进来,您就有了要给文件类对象。可是,该对象中还有一些额外的特性,它们可以使您得到一些关于接收到的数据的其他细节。下面掩饰这个的程序。



有些站点需要HTTP认证后才能访问。最普通的认证类型是基本认证,由客户端想服务器发送一个用户名和密码。HTTP认证一般显示一个弹出窗口,来询问用户名和密码。它与基于cookie和fom的认证是不同的。






总结: python的urllib2模块为从多种来源获得的数据提供了一个非常方便的接口。默认情况下,它对具备或不具备SSL的HTTP\FTP\Gopher都支持。他的最基本用途就是从Internet上下载Web页面和文件。

有些站点需要经过认证后才能访问。通过构建您自己URL访问者和定义密码管理的类,您可以在需要的时候提示用户输入认证信息。

使用URLLIB2,您还可以提交表单数据。这又两种方法:Get和POST.

与其他Python模块一样,当有错误发生时,urllib2也会产生异常。这包括几种不同类型的异常。






解析HTML和XHTML

超文本语言(HTML)和它的亲戚——可扩展的超文本语言(XHTML)是WEB上的主要语言。当您浏览一个Web页面的时候,该页面很有可能是由HTML和XHTML来呈现的。设计这些标记语言的目的是为了在Web浏览器里展示信息。然而,有时候您会发现需要从某个WEB页面上摘录一些信息,因为没有比这更好的办法来取得信息了。


从WEB页面上摘取信息来给人看,是一件困难的事情。首先您需要找到适合计算机处理的数据源。有时候,你会找到用都好分隔的文件或XML文件,他们反而比较容易处理。


HTML是分级别的,这就意味着解析程序需要在标签出现的时候 ,就会知道上下文的内容。如果解析程序使用一些传统的方法,例如正则表达式,那么将是很困难的。而事实上,很多HTML页面并不完全服务好HTML标准,这就更复杂了。PYTHON提供了HTMLParser模块,它可以让您非常简单地解析HTML。


XHTML表示一种有趣的混合数据格式。XHTML的目的是和HTML兼容,同事可以按照真正的xml来解析。


HTMLParser是几种可以用来解析HTML的方法之一。为了用HTMLParser模块来解析,您一般需要定义一个子类HTMLParser.HTMLParser,并添加用来处理不同标签的函数。作为一个例子,让我们考虑如何从下main的HTML文档中取得标题(title)


程序定义了一个TitleParser类,它是标准HTMLParser类的子孙。HTMLParser()的feed()方法会适当地调用handle_starttag()、handle_data()和 handle_endtag()方法。handle_data()方法会检查是否从TITLE元素中取得数据,如果是,就保存。


前面的代码能将手边上简单、组织结构好的文档处理得很好。然而,并不是所有的HTML都这么简单,也并不是所有被称为HTML的文档都只含有有效的HTML语言。当今的WEB浏览器对于不标准的HTML非常宽容,作为一个不幸的逻辑,现在在INTERNET上有太多不标准的HTML,您的程序必须处理这个。



翻译实体

HTML中的实体表示正规的字符。例如有个HTML实体 &amp ,表示 &。当为了工作而现实HTML代码的时候通常您希望把这些HTML实体转换为纯文本格式。


下面是一个考虑实体的例子


PYTHON很方便地在htmlentitydefs类中提供了HTML实体的映射。这个程序只是简单地使用这个映射来进行相关的转换。当出现一个实体的时候,代码检查该实体是否可识别。如果可以,则转换为相应的值。否则,就使用输入流中的文字值。这是因为人们在HTML中经常忘记使用&amp,而只用&,并以一个无效的实体结束。


除了实体之外,HTML文件还包含字符参考。他们包含字符的十进制数值,看上去类似 &#174. 像这样的自负参考是用来潜入那些不能打印的字符的。例如:非英文的文档会包含某些特定字符的字符参考;英文文档也会包含一些特殊符号的字符参考。转换他们是很直接的。



除了从文档中摘录标题和列表之外,HTMLParser还可以做很多其他的事情。它还可以用来解析表,从巨大的WEB也main中摘录有趣的小块儿内容,以及其他一些任务。


为了演示使用HTMLParser完成任务,这里有个例子,它可以链接到一个真实的站点,然后根据您所在地的邮编下载当前的天气和预报。程序接着处理这个页面,找到您感兴趣的部分,然后在屏幕上以表格的形式呈现出来。



xml

xml文档是层次结构的。大多数的文档都是书的一部分。书有标题,还有章节,还包括作者的信息。因为标签name在《author》部分,所以您就是知道它指的是作者

与HTML不同的是,XML的规格说明书中并没有提到那些是有效的标签,以及哪些标签是必须用的。作为文档的作者,您可以发明自己的标签,并随时使用它们。


然而,很多标准是建立在XML之上的,他们是定义了一些有效标签的。

通常,当您使用XML文档的时候,您会使用一个预先定义好的XML解析库。这些库通常使用下面两种方法之一来展示XML文档:tree 和 event 一个基于事件的解析器可以扫描文档,并在您感兴趣的内容出现的时候通知您。对于一个基于事件的解析器,您可以实现编写好文档中出现您感兴趣的事情的时候,程序该做什么。


另一方面,基于树的解析器会扫描全部的文档,通过产生嵌套的数据结构来展示文档。对于一个树的解析器,您可以在得到解析的结果后,浏览一下并跳出您需要的信息。另外一个基于树的有点是,您可以在把数据存入内存后进行修改,并通过系统把修改后的XML文档写到磁盘上。


Python对于这两种方法都支持。它的SAX模块可以实现基于事件的解析。他的DOM模块可以实现基于树的解析。其他面向语言中也包含SAX和DOM。


DOM最主要的有点事它能够呈现给您一个完整的,可以工作的xml文档树,尽管对于非常大的XML来说,这会有问题。因此,您可以使用命令有效地执行类似“给出当前节点下所有的节点”的命令。这是一个非常有用的特性,可以为您节省很多编程时间。








EMAIL的编写和编码








  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值