python学习笔记_19(网络编程)

网络编程


1. 网络编程基础模块
  • socket模块
    • 网络编程中基本组件就是嵌套字(socket),嵌套字基本上就是两个端点的程序之间的“信息通道”。python中嵌套字主要使用socket模块。

    • 嵌套字包括服务端嵌套字和客户端嵌套字,服务端在创建嵌套字等待连接,客户端通过ip和端口连接服务端

    • 一个嵌套字就是socket模块中socket类的一个实例,实例化时需要3个参数,对于普通嵌套字,不需要提供任何参数

      参数默认值可选值
      第一个参数地址族socket.AF_INETAF_UNIX
      第二个参数流socket.SOCK_STREAMsocket.SOCK_DGRAM - 数据报
      第三个参数协议0
    • 实例化一个socket后,服务端使用bind绑定主机地址和端口,在调用listen方法开始监听,客户端则使用connect方法连接到服务器,connect方法中使用的地址与服务器bind方法中的地址相同。

    • listen方法只有一个参数,服务器未处理的连接的长度(即允许排队等待的连接数目)。

    • 一个地址就是格式为(host, port)的元组,服务端可以使用socket.gethostname得到当前的主机名

    • 服务端开始监听后接收客户端的连接,使用accept方法来完成,accept方式是阻塞式的,连接建立后返回一个(client, address)的元组,client是客户端嵌套字,address是地址元组。

    • 嵌套字传输数据是使用send和recv方法,recv使用所需的最大字节数参数来接收数据,send使用字符串参数发送数据

  • urllib和urlib2
    • urllib有基础的功能,urllib2包括了http验证或cookie等功能

      # urllib使用
      >>> from urllib import urlopen
      >>> webpage = urlopen('http://www.python.org')
      
      #urlopen返回的是一个类文件对象,支持close,read,readline和readlines
      >>> import re
      >>> text = webpage.read()
      >>> m = re.search('<a href="([^"]+)" .*?>about</a>', text, re.IGNORECASE)
      >>> m.group(1)
      '/about'
      
      #获取远程文件urlretrieve, 返回一个元组(filename, headers)
      urlretrieve('http://www.python.org', r'c:\python_webpage.html')
      
  • 其他模块
    模块描述
    asynchatasyncore的增强版
    asyncore异步嵌套字处理程序
    cgi基本的CGI支持
    CookieCookie对象操作,主要用于服务器
    Cookielib客户端Cookie支持
    emailE-mail消息支持(包括MIME)
    ftplibFtp客户端模块
    gopherlibgopher客户端模块
    httplibHTTP客户端模块
    imaplibIMAP4客户端
    mailbox读取几种邮箱的格式
    mailcap通过mailcap文件访问MIME配置
  • SocketServer模块

    • SocketServer模块是标准库中很多服务器框架的几次,增加了服务端socket的特定功能

    • SocketServer封装了4个类,针对TCP的TCPServer,针对UDP的UDPServer,以及UnixStreamServer和unixDatagramServer

      # SocketServer使用方法
      # 编写使用SocketServer框架的服务,大部分代码放在一个请求处理程序中(request handler)
      # 每当服务器收到一个请求,就会实例化一个请求处理程序,并各种处理方法(handler method)会在处理请求时被调用
      
      #socket_server_demo.py
      class Handler(StreamRequestHandler):
      
          def handle(self):
              addr = self.request.getpeername()
              print 'Got connection from', addr
              self.wfile.write('Thank you for connecting')
      
          
      def socket_server_demo():
          #host = socket.gethostname()
          server = TCPServer(('', 1234), Handler)
          server.serve_forever()
          
      
      
      if __name__ == "__main__":
          #main()
          socket_server_demo()
          
      #socket_client.py
      import socket
      
      
      def main():
          s = socket.socket()
          host = socket.gethostname()
          port = 1234
          s.connect((host, port))
          print s.recv(1024)
      
      
      if __name__ == "__main__":
          main()
      
      
2. 同时多个连接
  • 分叉(forking)
  • 线程(threading)
  • 异步I/O(asynchronous)
# forking为linux/unix上的技术,fork一个进程时,基本上是负载它,属于多进程技术,windows上不支持

#! /bin/sh
# -*- coding: utf-8 -*-

# file name: socket_server_mixin


import time
from SocketServer import TCPServer, ForkingMixIn, StreamRequestHandler
from SocketServer import ThreadingMixIn

class ServerForking(ForkingMixIn, TCPServer):
    pass

class ServerThreading(ThreadingMixIn, TCPServer):
    pass

class Handler(StreamRequestHandler):

    def handle(self):
        addr = self.request.getpeername()
        print 'Got connection form', addr
        print 'waiting for 10s'
        time.sleep(10)
        self.wfile.write('Thank you for connecting')


if __name__ == "__main__":
    #forking方式
    s = ServerForking(('', 1234), Handler)
    # threading方式
    #s = ServerThreading(('', 1234), Handler)
    s.serve_forever()
  
# 3. 异步I/O,异步I/O的基础是select/poll函数,来自select模块,poll伸缩性很好,但只能用于unix系统
# select函数需要3个序列参数,分别是输入,输出,异常,序列是文件描述符整数或者有返回这样整数的fileno参数,第4个参数是单位为秒的超时时间,如果没有给seelect会阻塞,如果为0那么就给出一个连续的poll,返回长度为3的元组
#! /bin/sh
# -*- coding: utf-8 -*-

# file name: socket_server_select.py


import socket
import 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, [], [], 1)
    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
                
# 1. pool函数,调用是返回一个poll对象,使用poll对象register方法注册一个文件描述符或带有fileno的对象,注册后可以使用unregister方法移除,注册后调用poll方法(带有可选的的超时时间参数)并得到(fd, event)元组,fd是文件描述符,event事件,event为位掩码,不同的事件是select模块的常量
def socket_poll():
    s = socket.socket()
    host = socket.gethostname()
    port = 1234
    s.bind((host, port))

    fdmap = {s.fileno(): s}

    s.listen(5)

    p = select.poll()
    p.register(s)

    while True:
        events = p.poll()
        for fd, event in events:
            if fd == s.fileno():
                c, addr = s.accept()
                print 'Got connection from', addr
                p.register(c)
                fdmap[c.fileno()] = c
            elif event & select.POLLIN:
                data = fdmap[fd].recv(1024)
                if not data:
                    print fdmap[fd].getpeername, 'disconnected'
                    p.unregister(fd)
                    del fdmap[fd]
            else:
                print data
事件名描述
POLLIN读取来自文件描述符的数据
POLLPRI读取来自文件描述符的紧急数据
POLLOUT文件描述符已经准备好数据,写入时不会发生阻塞
POLLERR与文件描述符有关的错误情况
POLLHUP挂起,连接丢失
POLLNVAL无效请求,连接没有打开
3. Twisted
#! /usr/bin/python
# -*- coding: utf-8 -*-

#file name: socket_server_twisted.py

import socket
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, Factory
from twisted.protocols.basic import LineReceiver


class SimpleLogger(Protocol):

    def connectionMade(self):
        print 'get connection from', self.transport.client

    def connectionLost(self, reason):
        print self.transport.client, 'disconnected'

    def dataReceived(self, data):
        print data


class SimpleLineLogger(LineReceiver):

    def connectionMade(self):
        print '[Line recevier]', 'get connection from', self.transport.client
        self.sendLine('welcome to %s' % socket.gethostname())
        self.setLineMode()

    def connectionLost(self, reason):
        print '[Line recevier]', self.transport.client, 'disconnected'

    def lineReceived(self, line):
        print '[Line recevier]', line

   #def dataReceived(self, data):
   #     print '[Data recevier]', data

factory = Factory()
#factory.protocol = SimpleLogger
factory.protocol = SimpleLineLogger

reactor.listenTCP(1234, factory)
reactor.run()
#! /user/bin/python
# -*- coding: utf-8 -*-

# file name: socket_client.py


import socket


def main():
    s = socket.socket()
    #s.setblocking(False)
    #print 'default timeout', s.getdefaulttimeout()
    #s.setdefaulttimeout(1)
    #host = socket.gethostname()
    host = "192.168.1.198"
    port = 1234
    rlt = s.connect((host, port))
    #print rlt
    print 'Hello %s, %s\n' % s.getsockname()
    s.send('Hello %s, %s\r\n' % s.getsockname())
    print s.recv(1024),


if __name__ == "__main__":
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值