首页 > 代码库 > 【Python】网络编程

【Python】网络编程

1、TCP编程

2、SocketServer模块

3、Twisted框架

4、UDP编程

 

1、TCP编程——TCP是面向连接的,其一般的设计如下:

               image

 

# encoding:utf-8‘‘‘Created on 2014-6-20@author: Administrator‘‘‘from socket import          socket,          AF_INET,          SOCK_STREAMimport timeimport threadingclass SockServer(object):    def __init__(self, port):        self.HOST = "localhost"        self.PORT = port        self.SOCK = (self.HOST, self.PORT)        self.BUF = 1024        self._init()            def _init(self):        self.sock_server = socket(AF_INET, SOCK_STREAM)        self.sock_server.bind(self.SOCK)        self.sock_server.listen(100)            def __thread_process(self, sock_client, client_addr):        print "connected :", sock_client.getpeername()                    while True:            data = sock_client.recv(self.BUF)            if not data:                continue            elif data =http://www.mamicode.com/= "bye":                print "<< %s" % data                break            else:                sock_client.send([%s] %s % (time.ctime(), data))                print "%s << %s: %s" % (sock_client.getsockname(), client_addr, data)        sock_client.close()            """多线程并发服务器"""    def process(self):        while True:            print "waiting for connection..."            (sock_client, client_addr) = self.sock_server.accept()            threading.Thread(target=self.__thread_process, args=(sock_client, client_addr)).start()                def __del__(self):        self.sock_server.close()        if __name__ == "__main__":    port = 12345    server = SockServer(port)    server.process()

 

客户端一般设计:

image

# encoding:utf-8‘‘‘Created on 2014-6-20@author: Administrator‘‘‘from socket import socket, AF_INET, SOCK_STREAMclass SockClient(object):    def __init__(self, ip, port):        self.IP = ip        self.PORT = port        self.SOCK = (ip, port)        self.BUF = 1024        self._init()        def _init(self):        self.sock_client = socket(AF_INET, SOCK_STREAM)    def process(self):        print "connecting server..."        self.sock_client.connect(self.SOCK)        while True:            data = raw_input(">>")            self.sock_client.send(data)            if data.strip() == "bye":                break            recv_data = self.sock_client.recv(self.BUF)            if not recv_data:                print "no recv!"            else:                print recv_data                def __del__(self):        self.sock_client.close()        if __name__ == "__main__":    ip = "localhost"    port = 12345    client = SockClient(ip, port)    client.process()

 

2、SocketServer模块——用于简化实现网络编程客户端与服务器所需要的大量样板代码。

2.1 创建一个SocketServerTCP服务器:

# encoding:utf-8‘‘‘Created on 2014-6-23@author: Administrator‘‘‘from time import ctimefrom SocketServer import TCPServer, StreamRequestHandler"""    SocketServer 的请求处理器默认行为时接收连接,得到请求,然后关闭连接,这使得我们不能    在程序运行时,一直保持连接状态,而是每次发送数据到服务器的时候创建一个新的套接字"""class MyRequestHandle(StreamRequestHandler):    """                客户端有消息发来时,handle函数会被调用    """    def handle(self):        print "...connecting from :", self.client_address        self.wfile.write([%s] %s % (ctime(), self.rfile.readline()))if __name__ == "__main__":    ip = "localhost"    port = 12345    tcpServ = TCPServer((ip, port), MyRequestHandle)    print "waiting for connection..."    tcpServ.serve_forever()

说明:

        1、这里的主要工作是从SocketServer的StreamRequestHandler类派生出一个子类,并重写handle()函数。

在有客户端消息近来的时候,handle()函数就会被调用,如上是一个使用SocketServer模块的回射服务器例子。

       2、SocketServer的请求处理器的默认行为时接收连接,得到请求,然后关闭连接,这使得我们不能再程序运行时,一致保持连接状态,

而是每次发送数据到服务器的时候都要创建一个新的套接字。

 

2.2 创建一个SocketServerTCP客户端:

# encoding:utf-8‘‘‘Created on 2014-6-23@author: Administrator‘‘‘from socket import socket, AF_INET, SOCK_STREAMclass SocketClient(object):    def handle(self, ADDR):        BUF = 1024        while True:            self.client = socket(AF_INET, SOCK_STREAM)            self.client.connect(ADDR)            data = raw_input(">>")            if not data:                break            self.client.send("%s\r\n" % data)   #服务端使用的是readline,为了保持一致,发送添加了换行            rcv_data =http://www.mamicode.com/ self.client.recv(BUF)            if not rcv_data:                break            else:                print rcv_data.strip()            self.client.close()                self.client.close()if __name__ == "__main__":    ip = "localhost"    port = 12345    client = SocketClient()    client.handle((ip, port))

说明:

        1、本例子是针对使用SocketServer的服务端的例子,其中send()函数需要添加”\r\n”换行符,对应于服务器端的readline()函数

        2、发送数据之后,断开连接,因为SocketServer的默认行为使得不能再程序运行时,一致保持连接状态

运行结果:

          服务端:

                  image

          客户端:

                    image

 

3、Twisted框架

   简介——Twisted是一个完全事件驱动的网络框架,允许使用和开发完全异步的网络应用程序和协议。

  3.1 安装Twisted扩展(Windows)

       下载:Twisted和zope

       http://twistedmatrix.com/trac/wiki/Downloads

 

      安装Twisted扩展(Linux)

      命令:easy_install twisted

     Linux_twisted

 

     eclipse pydev添加twisted模块:

        系统已经安装twisted模块,导入twisted,引用其中的方法时,出现如下情况:

         clip_image001

       解决方法是:

                在Eclipse的Window—Preferences—PyDev—Interpreter-Python 窗口下的Forced Buildins添加twisted

                clip_image003

       即可正常引用twisted包

 

3.2 Twisted服务端:

# encoding:utf-8‘‘‘Created on 2014-6-23@author: Administrator‘‘‘from twisted.internet import reactor, protocolfrom time import ctime"""    Twisted 是一个完全事件驱动的网络框架,允许使用和开发完全异步的网络应用程序和协议"""class TwistedServer(protocol.Protocol):        """                    重写connectionMade函数,该函数在有客户端连接时被调用    """    def connectionMade(self):        client = self.client = self.transport.getPeer().host        print "...connected from ", client, ":", self.transport.getPeer().port    """                    该函数在客户端通过网络发送数据过来时被调用    """    def dataReceived(self, data):        self.transport.write("[%s] %s" % (ctime(), data))if __name__ == "__main__":    port = 12345    factory = protocol.Factory()    factory.protocol = TwistedServer    print "waiting for connection..."    reactor.listenTCP(port, factory)    reactor.run()

说明:

          Twistede服务端从Protocol类派生子类,然后重写connectionMade()函数,这个函数在有客户端连接的时候被调用,dataReceived()函数,这个函数在客户端

通过网络发送数据过来的时候被调用,reactor把数据当成参数传到这个函数中

 

3.3 Twisted客户端

# encoding:utf-8‘‘‘Created on 2014-6-23@author: Administrator‘‘‘from twisted.internet import protocol, reactorclass TwistedClient(protocol.Protocol):        def _senddata(self):        data = raw_input(">>")        if data:            print "...sending %s..." % data            self.transport.write(data)        else:            self.transport.loseConnection()        #连接建立之后,调用自定义_senddata函数    def connectionMade(self):        self._senddata()        def dataReceived(self, data):        print data        self._senddata()class TClientFactory(protocol.ClientFactory):    protocol = TwistedClient    clientConnectionLost = clientConnectionFailed =     lambda self, connector, reason:reactor.stop()    if __name__ == "__main__":    host = "localhost"    port = 12345    reactor.connectTCP(host, port, TClientFactory())    reactor.run()

说明:

      Twisted客户端也从Protocol派生子类,重写connectionMade()和dataReceived()函数,当用户没有任何输入时(参考如上代码中_senddata()函数中else部分),连接结束,结束时,调用loseConnection关闭套接字,这时工厂的clientConnectionLost函数会被调用,同时reactor就被关闭,脚本执行就结束了,由于某些原因,clientConnectionFailed()被调用时,reactor也会被关闭。

 

4. UDP 编程

   UDP是无连接的,服务器一般设计如下:

         image

4.1 服务器端编程

# encoding:utf-8‘‘‘Created on 2014-6-20@author: Administrator‘‘‘                from socket import         socket,         AF_INET,         SOCK_DGRAMfrom time import ctime        class DgramServer(object):    def __init__(self, port):        self.HOST = "localhost"        self.PORT = port        self.SOCK = (self.HOST, self.PORT)        self.BUF = 1024        self._init()            def _init(self):        self.dgram_server = socket(AF_INET, SOCK_DGRAM)        self.dgram_server.bind(self.SOCK)            def process(self):        print "waiting for message..."        while True:            data, addr = self.dgram_server.recvfrom(self.BUF)            print "<<",addr, ":%s " % data            if data =http://www.mamicode.com/= "bye":                break            self.dgram_server.sendto("[%s,%s]" % (ctime(), data), addr)                def __del__(self):        self.dgram_server.close()        if __name__ == "__main__":    port = 12345    dgram = DgramServer(port)    dgram.process()

注意:

      UDP服务端,recvfrom会返回连接的地址

 

4.2 客户端编程

# encoding:utf-8‘‘‘Created on 2014-6-20@author: Administrator‘‘‘from socket import         socket,         AF_INET,         SOCK_DGRAMclass DgramClient(object):    def __init__(self, ip, port):        self.HOST = ip        self.PORT = port        self.SOCK = (self.HOST, self.PORT)        self.BUF = 1024        self._init()            def _init(self):        self.dgram_client = socket(AF_INET, SOCK_DGRAM)            def process(self):        while True:            data = raw_input("<<")            self.dgram_client.sendto(data, self.SOCK)            if data =http://www.mamicode.com/= "bye":                    break            recv_data, dgram = self.dgram_client.recvfrom(self.BUF)            if not recv_data:                print "no recv"            else:                print ">>", dgram, ":%s" % recv_data        def __del__(self):        self.dgram_client.close()        if __name__ == "__main__":    ip = "localhost"    port = 12345    dgram = DgramClient(ip, port)    dgram.process()

运行结果:

         服务端:

        image

 

        客户端1:

        image

        客户端2:

         image