当前位置: 移动技术网 > IT编程>脚本编程>Python > Python 网络编程说明第1/2页

Python 网络编程说明第1/2页

2019年04月05日  | 移动技术网IT编程  | 我要评论

云轩阁,龙族3黑月之潮下,重庆到奉节坐船


例如,对于一个聊天室来说,因为有多个连接需要同时被处理,所以很显然,阻塞或同步的方法是不合适的,这就像买票只开了一个窗口,佷多人排队等一样。那么我们如何解决这个问题呢?主要有三种方法:forking、threading、异步i/o。

forking和threading的方法非常简单,通过使用socketserver服务类的min-in类就可以实现。forking只适用于类unix平台;threading需要注意内存共享的问题。
异步i/o如果底层的方法来实现是有点困难的。要简单点,我们可以考虑使用标准库中的框架或twisted(twisted是一个非常强大的异步网络编程的框架)。

一、用scoketserver实现forking和threading

下面我们使用两个例子来分别创建forking服务器和threading服务器。

forking 服务器:

from socketserver import tcpserver, forkingmixin, streamrequesthandler

class server(forkingmixin, tcpserver): pass

class handler(streamrequesthandler):
def handle(self):
addr = self.request.getpeername()
print 'got connection from', addr
self.wfile.write('thank you for connecting')

server = server(('', 1234), handler)
server.serve_forever()

threading服务器:

from socketserver import tcpserver, threadingmixin, streamrequesthandler

class server(threadingmixin, tcpserver): pass

class handler(streamrequesthandler):
def handle(self):
addr = self.request.getpeername()
print 'got connection from', addr
self.wfile.write('thank you for connecting')

server = server(('', 1234), handler)
server.serve_forever()

二、使用select实现异步i/o

所谓异步i/o,打个比方,就是如果一大群人都想你听他说话,那么你就给他们每人一分钟的时间说,大家轮流说,没说完的待会儿轮到时再继续说。也就是一个时间片的方法。

要实现异步i/o,我们可以通过使用框架asyncore/asynchat或twisted,它们都是基于select函数或poll函数(poll只适于类unix系统)的。select和poll函数都来自select模块。

select 函数要求三个必须序列作为参数和一个可选的以秒为单位的超时值。序列中是表示文件描述符的整数值,它们是我们要等待的连接。这三个序列是关于输入、输出和 异常条件的。如果超时值没有给出的话,select将处于阻塞状态(也就是等待)直到有文件描述符准备动作。如果超时值给出了,那么select只阻塞给 定的时间。如果超时值是0的话,那么将不阻塞。select返回的值是一个由三个序列组成的元组,它们分别代表相应参数的活动的子集。例如,第一个序列返 回的是用于读的输入文件描述符构成的序列。

序列可以包含文件对象(不适于windows)或socket。下面这个例子创建一个使用 select去服务几个连接的服务器(注意:服务端的socket自身也提供给了select,以便于它能够在有新的连接准备接受时发出信号通知)。这个 服务器只是简单地打印接受自客户端的数据。你可以使用telnet(或写一个基于socket的简单的客户端)来连接测试它。

select server

import socket, select

s = socket.socket()
host = socket.gethostname()
port = 1234
s.bind((host, port))

s.listen(5)
inputs = [s]
while true:
rs, ws, es = select.select(inputs, [], [])
for r in rs:
if r is s:
c, addr = s.accept()
print 'got connection from', addr
inputs.append(c)
else:
try:
data = r.recv(1024)
disconnected = not data
except socket.error:
disconnected = true

if disconnected:
print r.getpeername(), 'disconnected'
inputs.remove(r)
else:
print data


三、twisted

twisted 是针对python的一个事件驱动的网络框架,最初是为了网络游戏而开发的,但是现在被应用于各类网络软件。用twisted,你可以实现事件处理器,非 常类似用gui工具包(tk, gtk, qt, wxwidgets)。这部分我将介绍一些基本的概念和演示如何使用twisted来做一些相对简单的 网络编程。twisted是非常强大的框架并提供了大量的支持,如:web服务器和客户端、 ssh2, smtp, pop3, imap4, aim, icq, irc, msn,jabber, nntp, dns等等。

早先我们所写的基于socket的服务器,它们都有一个显示的事件循环:寻找新的连接和新的数据;基于socketserver的服务器有一个隐含的循环:寻找连接和为连接创建处理器。但时处理器仍然时显示的读数据。

而 twisted使用了更多的基于事件的方式。要写一个基本的服务器,你要实现事件处理器,它处理诸如一个新的客户端连接、新的数据到达和客户端连接中断等 情况。在twisted中,你的事件处理器定义在一个protocol中;你也需要一个factory,当一个新的连接到达时它能够构造这个 protocol对象,但是如果你仅仅想创建一个自定义的protocol类的实例的话,你可以使用来自twisted的factory,factory 类在模块twisted.internet.protocol中。当你写你的protocol时,使用 twisted.internet.protocol模块中的protocol作为你的父类。当你得到一个连接时,事件处理器 connectionmade被调用;当你丢失了一个连接时,connectionlost被调用。从客户端接受数据使用处理器 datareceived。但是你不能使用事件处理策略向客户端发送数据;要向客户端发送数据,你可以使用self.transport,它有一个 write方法。它也有一个client属性,其中包含了客户端的地址(主机名和端口)。

下面这个例子是一个twisted版的服务器。 其中实例化了factory并设置了它的protocol属性以便它知道使用哪个protocol与客户端通信(这就是所谓的你的自定义 protocol)。然后你使用factory开始监听指定的端口,factory通过实例化的protocol对象处理连接。监听使用reactor模 块中的listentcp函数。最后,你通过调用reactor模块中的run函数来开始服务器。

from twisted.internet import reactor
from twisted.internet.protocol import protocol, factory

# 定义你protocol类
class simplelogger(protocol):

def connectionmade(self):
print 'got connection from', self.transport.client
def connectionlost(self, reason):
print self.transport.client, 'disconnected'
def datareceived(self, data):
print data


# 实例化factory

factory = factory()

# 设置factory的protocol属性以便它知道使用哪个protocol与客户端通信(这就是所谓的你的自定义
# protocol)

factory.protocol = simplelogger

# 监听指定的端口

reactor.listentcp(1234, factory)

# 开始运行主程序
reactor.run()

为 你的处理目的而写一个自定义的protocol是很容易的。模块twisted.protocols.basic中包含了几个有用的已存在的 protocol,其中的linereceiver执行datareceived并在接受到了一个完整的行时调用事件处理器linereceived。如 果当你在接受数据时除了使用linereceived,还要做些别的,那么你可以使用linereceiver定义的名为rawdatareceived 事件处理器。下面是一使用linereceiver的服务器例子:

from twisted.internet import reactor
from twisted.internet.protocol import factory
from twisted.protocols.basic import linereceiver

class simplelogger(linereceiver):

def connectionmade(self):
print 'got connection from', self.transport.client
def connectionlost(self, reason):
print self.transport.client, 'disconnected'
def linereceived(self, line):
print line

factory = factory()
factory.protocol = simplelogger
reactor.listentcp(1234, factory)
reactor.run()

urllib和urllib2

urllib 和urllib2的工作大同小异,它们让你能够通过网络访问文件,就像访问自己电脑上的一样。通过简单的函数调用,url所定位的资源就可以被你作为输入 使用到你的程序中。如果再配以re模块,那么你就能够下载web页面、提取信息、自动创建你所寻找的东西的报告。

urllib2更流行一些。对于简单的下载任务,urllib比较好。如果你需要http验证或cookies,或你想写一些扩展去处理你自己的协议的话,那么urllib2是正确的选择。

一、打开远程文件

打开远程文件的操作和本地差不多,不同的是只能使用读模式,并且使用urllib模块的urlopen:

>>> from urllib import urlopen
>>> webpage=urlopen('http://www.python.org')

如果你在线的话,变量webpage现在就包含了一个关联web页:http://www.python.org的文件类对象。
注意:如果你当前没有联网,而你又想练习一下urllib的话,你可以用如下形式访问本地文件:
localpage=urlopen(r'file:c:\test.txt')

由urlopen返回的文件类对象支持close,read,readline,readlines等方法。

下面的代码抽取出了python官方主页中“documentation”链接的url:

>>> import re
>>> text = webpage.read()
>>> m = re.search('<a href="([^"]+)">documentation</a>', text, re.ignorecase)
>>> m.group(1)
'http://docs.python.org/'

二、获取远程文件

urlopen 函数给你一个文件类对象,你可以读取它。如果你使用urlib时只关心下载文件并存储一个复本到本地文件的话,你可以使用urlretrieve替而代 之。urlretrieve返回一个元组(filename, headers),filename是本地文件(复本)的名字(它由urllib自动创 建),headers包含关于远程文件的一些信息。
如果你想为复本指定一个名字的话,你可以提供第二个参数:
urlretrieve('http://www.python.org', 'c:\\python_webpage.html')
这 将获取python官方主页并存储到本地c:\python_webpage.html中。如果你不指定复本的文件名,那么文件将放到一个临时的地方,你 能够使用open函数打开它,如果你要清除这些临时的复本,你可以调用urlcleanup函数而不带任何参数,它将为你完成清除工作。


一、套接字
套接字是为特定网络协议(例如tcp/ip,icmp/ip,udp/ip等)套件对上的网络应用程序提供者提供当前可移植标准的对象。它们允许程序接受并进行连接,如发送和接受数据。为了建立通信通道,网络通信的每个端点拥有一个套接字对象极为重要。

套接字为bsd unix系统核心的一部分,而且他们也被许多其他类似unix的操作系统包括linux所采纳。许多非bsd unix系统(如ms-dos,windows,os/2,mac os及大部分主机环境)都以库形式提供对套接字的支持。

三种最流行的套接字类型是:stream,datagram和raw。stream和datagram套接字可以直接与tcp协议进行接口,而raw套接字则接口到ip协议。但套接字并不限于tcp/ip。

二、套接字模块

套接字模块是一个非常简单的基于对象的接口,它提供对低层bsd套接字样式网络的访问。使用该模块可以实现客户机和服务器套接字。要在python 中建立具有tcp和流套接字的简单服务器,需要使用socket模块。利用该模块包含的函数和类定义,可生成通过网络通信的程序。一般来说,建立服务器连接需要六个步骤。

第1步是创建socket对象。调用socket构造函数。

socket=socket.socket(familly,type)

family的值可以是af_unix(unix域,用于同一台机器上的进程间通讯),也可以是af_inet(对于ipv4协议的tcp和 udp),至于type参数,sock_stream(流套接字)或者 sock_dgram(数据报文套接字),sock_raw(raw套接字)。

第2步则是将socket绑定(指派)到指定地址上,socket.bind(address)

address必须是一个双元素元组,((host,port)),主机名或者ip地址+端口号。如果端口号正在被使用或者保留,或者主机名或ip地址错误,则引发socke.error异常。

第3步,绑定后,必须准备好套接字,以便接受连接请求。

socket.listen(backlog)

backlog指定了最多连接数,至少为1,接到连接请求后,这些请求必须排队,如果队列已满,则拒绝请求。

第4步,服务器套接字通过socket的accept方法等待客户请求一个连接:

connection,address=socket.accept()

调用accept方法时,socket会进入'waiting'(或阻塞)状态。客户请求连接时,方法建立连接并返回服务器。accept方法返回一个含有俩个元素的元组,形如(connection,address)。第一个元素(connection)是新的socket对象,服务器通过它与客户通信;第二个元素(address)是客户的internet地址。

第5步是处理阶段,服务器和客户通过send和recv方法通信(传输数据)。服务器调用send,并采用字符串形式向客户发送信息。send方法返回已发送的字符个数。服务器使用recv方法从客户接受信息。调用recv时,必须指定一个整数来控制本次调用所接受的最大数据量。recv方法在接受数据时会进入'blocket'状态,最后返回一个字符串,用它来表示收到的数据。如果发送的量超过recv所允许,数据会被截断。多余的数据将缓冲于接受端。以后调用recv时,多余的数据会从缓冲区删除。

第6步,传输结束,服务器调用socket的close方法以关闭连接。

建立一个简单客户连接则需要4个步骤。

第1步,创建一个socket以连接服务器 socket=socket.socket(family,type)

第2步,使用socket的connect方法连接服务器 socket.connect((host,port))

第3步,客户和服务器通过send和recv方法通信。

第4步,结束后,客户通过调用socket的close方法来关闭连接。


三、一个简单的服务器和客户端通信的例子

服务器:


import socket
s=socket.socket()
s.bind(('xxx.xxx.xxx.xxx',xxxx)) #ip地址和端口号
s.listen(5)
cs,address = s.accept()
print 'got connected from',address
cs.send('byebye')
ra=cs.recv(512)
print ra
cs.close()


客户端:


import socket
s=socket.socket()
s.connect(('xxx.xxx.xxx.xxx',xxxx)) #与服务器程序ip地址和端口号相同
data=s.recv(512)
s.send('hihi')
s.close()
print 'the data received is',data


运行:

在本机测试(windows环境下,可以将ip地址改为本机ip,端口号在1024以上,windows将1024以下的为保留),运行--cmd--进入命令行模式

先python 服务器程序,后python 客户端程序即可。

或者启动服务器程序后,用telnet ip地址 端口号,也可以得到同样结果。


--------------------------------------------------------------------------------
让server持续接受连接

server.py


import socket
s=socket.socket()
s.bind(('192.168.43.137',2000))
s.listen(5)

while 1:
cs,address = s.accept()
print 'got connected from',address
cs.send('hello i am server,welcome')
ra=cs.recv(512)
print ra
cs.close()


测试两个一个程序中两个socket并存是否可行

client.py
import socket
s=socket.socket()
s.connect(('192.168.43.137',2000))
data=s.recv(512)
print 'the data received is\n ',data
s.send('hihi i am client')

sock2 = socket.socket()
sock2.connect(('192.168.43.137',2000))
data2=sock2.recv(512)
print 'the data received from server is\n ',data2
sock2.send('client send use sock2')
sock2.close()

s.close()


网络编程框架2009年04月12日 星期日 上午 10:39twisted是python里面公认的很牛的网络编程框架。学python网络编程的如果不学twisted,估计也就只能算是了解python网络编 程吧,就如同开发网站要用django是一样的,二者都是python下有名的框架。twisted是基于单线程的事件驱动的网络引擎。关于它的学习资料 比较少,而且中文的就更少了,所以学习twisted一定要硬着头皮看英文文档,也就是它的twisted documentation,在这里基本可以找到你所需要的所有基础知识。尤其是core documentation 和example里面都讲了很多示例,这些示例如果都通通的运行一遍,那么你的twisted已经可以算入门了。
我主要是用twisted的工厂和协议框架编写了一个内部的内容分发网络的tracker服务器,不是基于标准bt协议的,如果要学习,最好还是按照标准bt协议。前面也给了网址。至于如何使用twisted,我会在后续文章详细介绍。

本文先介绍twisted的两种工作方式,reactor 和 application方式。
the reactor is the core of the event loop within twisted -- the loop which drives applications using twisted. the reactor provides basic interfaces to a number of services, including network communications, threading, and event dispatching.
reactor是twisted事件循环的核心,它提供了一些服务的基本接口,像网络通信、线程和事件的分发。
详细的关于reactor的介绍见twisted core documentation里面的low-level twisted一章的第一节reactor overview.里面详细介绍了各种reactor的安装和使用。
我所知道的reactor有以下几个
reactor platform usage
iocpreactor win32 from twisted.internet import iocpreactor iocpreactor.reactor.install()

from twisted.internet import reactor
selectreactor win32, posix from twisted.internet import reactor
pollreactor posix from twisted.internet import pollreactor
pollreactor.install()

from twisted.internet import reactor
epollreactor linux2.6 from twisted.internet import epollreactor
epollreactor.install()

from twisted.internet import reactor
kqueuereactor bsd系列 from twisted.internet import kqreactor
kqreactor.install()

from twisted.internet import reactor
以上几种就是使用最多的几种reactor了,除了kqueuereactor我没有使用过以外,其他的都使用过了。都能正常工作。建议编程序的时候实现根据不同的平台选择最佳的reactor。
系统默认使用的是selectreactor。

下面给出一个小例子:
from twisted.internet.protocol import protocol, factory
from twisted.internet import reactor

### protocol implementation

# this is just about the simplest possible protocol
class echo(protocol):
def datareceived(self, data):
"""as soon as any data is received, write it back."""
self.transport.write(data)


def main():
f = factory()
f.protocol = echo
reactor.listentcp(8000, f)
reactor.run()

if __name__ == '__main__':
main()

2

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网