• 【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_STREAM
    
    import time
    import threading
    
    class 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 == "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_STREAM
    
    class 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 ctime
    from 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_STREAM
    
    class 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
    " % data)   #服务端使用的是readline,为了保持一致,发送添加了换行
                rcv_data = 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()函数需要添加” ”换行符,对应于服务器端的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, protocol
    from 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, reactor
    
    
    class 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_DGRAM
    
    from 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 == "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_DGRAM
    
    class 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 == "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

  • 相关阅读:
    C#各自定义控件的网址链接
    给应用程序加装“看门狗”
    CRT detected that the application wrote to memory after after the end of heap buffer(这个经常忘掉)
    关于C#中的Delegate的一些知识
    实行项目管理信息化的好处
    C#连接池的详细分析(转)
    .Net Remoting和Web Service大比拼(转)
    使用SqlDataSource调用带参数存储过程插入数据
    156转换为byte时为什么会变成100的解释
    站在“组织者”这个角色上
  • 原文地址:https://www.cnblogs.com/luosongchao/p/3807881.html
Copyright © 2020-2023  润新知