• python IO编程、线程和进程、网络编程


    1.Socket类型

           套接字格式为:socket(family,type[,protocal]]),使用给定的地址族,套接字类型、协议编号来创建套接字

          socket.AF_UNIX   只能够用于单一的Unix系统进程间通信

           socket.AF_INET 服务器之间网络通信

            socket.AF_INNET6   IPv6

             socket.SOCKET_STREAM   流式socket,用于TCP

             socket.SOCK_RAW 原始套接字,普通的套接字无法理解ICMP,IGMP等网络报文,而SOCK_RAW可以,其次,SOCK_RAW也可以理解特殊的

    Ipv4报文,利用原始套接字可以通过IP_HDRINCL套接字选项由用户构造IP头

             创建TCP Socket      s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

             创建UDP Socket   s=socket.socket(socket.AF_INET,socket.SOck_DGRAM)

              常用变成函数

         服务端Socket函数                 s.bind(address)    将套接字绑定到地址,在AF_INET下,以元组(host,port)的形式表示地址

              s.listen(backlog) 开始监听TCP传入连接。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设置为5

              s.accept()   接受TCP连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送消息,address是连接客户端的地址

            客户端Socket函数

             s.connect(address) 连接到address处的套接字。一般address的格式为元组(hostname,port) ,如果连接出错,返回socket.error错误

             s.connect_ext(address) 功能与connect(address)相同,但成功返回0,失败返回error的值

           公共Socket函数

            s.recv(buflen,flage) :接受TCP套接字的数据,数据以字符形式返回,buflen指定要接收的最大数据量,flage提供有关消息的其他信息

            s.send(string,flage) 发送TCP数据,将string中的数据发送到连接的套接字,返回值是要发送的字节数,该数量可能小于string的字节大小

            s.sendall(string,flage)    完整发送TCP数据,将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据,成功返回None,失败抛出一哦下行

           s.recvfrom(buflen,flage) 接受UDP套接字的数据,与recv()类似,但返回值是(data,address).其中data 是包含接受数据的字符串,address是发送数据的套接字地址

           s.sendto(string,flage,address) 发送UDP数据。将数据发送到套接字,address是形式为(ipadder,port)的元组,指定远程地址,返回值是发送的字节数

          s.close() 关闭套接字

          s.getpeername() 返回连接套接字的远程地址 。返回值通常是元组(ipadder,port)

          s.getsockname() 返回套接字自己的地址,通常是一个元组(ipadder,port)

          s.setsockopt(level,optname,value) 设置给定套接字选项的值

          s.getsockopt() 返回套接字选项的值

           s.settimeout(timeout) 设置套接字操作的超时时间,timeout是一个浮点数,单位是秒。值为None表示没有超时,一般超时应该在创建链接字

    时设置,因为热他们可能会用于连接操作

     s,setblocking(flage) 如果flage值为0,则将套接字设置为非阻塞模式,否则将设置为阻塞模式,默认是阻塞模式,在非阻塞模式下,如果调用方

    recv()没有发现任何数据,或send()调用无法立即发送数据,将引起socket.error异常

    TCP编程:面向连接的编程方式   消息可靠

            服务端程序编写

                         1)创建Socket,绑定Socket到本地IP与端口

                         2)开始监听连接

                          3)进入循环,不断接收客户端的连接请求

                         4)接收传来的数据,并发送给对方数据

                         5)传输完成关闭Socket

               

    import socket
    import threading
    import time
    
    
    # 第四步:接收传来的数据,并发送给对方数据
    def dealClient(sock, addr):
        print('Accept new connection from %s:%s.....' % addr)
        sock.send(b'Hello, I am server!')
        while True:
            data = sock.recv(1024)
            time.sleep(1)
            if not data or data.decode('utf-8') == 'exit':
                break
            print('----->>%s!' % data.decode('utf-8'))
            sock.send(b'Loop Msg: %s!' % data.decode('utf-8').encode('utf-8'))  # 只能传送bytes
        # 第五部关闭Socket
        sock.close()
        print('Connection from %s:%s closed.' % addr)
    
    
    if __name__ == '__main__':
        # 第一步:创建一个基于IPv4和TCP协议的Socket
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(('127.0.0.1', 9999))
        # 第二步:监听
        s.listen(5)
        print('Waiting for connection......')
        while True:
            print('-----------------')
            # 第三步:接收一个新连接:
            sock, addr = s.accept()  # 等待一个链接的到来,会一直等待
            # 创建新线程来处理TCP连接
            t = threading.Thread(target=dealClient, args=(sock, addr))
            t.start()
    View Code

        客户端程序编写

                         1)创建Socket,连接远端地址

                          2)连接后发送数据和接收数据

                          3)传输完毕后,关闭Socket

    import socket
    import  time
    import  random
    #初始化Socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #连接目标IP和端口
    s.connect(('127.0.0.1',9999))
    time.sleep(random.random())
    #接收消息
    print('---->>',s.recv(1024).decode('utf-8'))#没有消息就会一直等待,或者知道进程结束
    #发送消息
    s.send(b'Hello,I am a client1')
    print('--->>',s.recv(1024).decode('utf-8'))
    s.send(b'exit')
    #关闭Socket
    s.close()
    View Code

          

    UDP编程

          服务器端

             1)创建Socket, 绑定指定的IP和端口

              2)直接发送数据和接收数据

             3)关闭Socket

    import socket
    
    # UDp服务进程
    
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.bind(('127.0.0.1', 9999))
    print('Bind UDP om 9999....')
    while True:
        data, addr = s.recvfrom(1024)
        print('Message is %s' % data.decode('utf-8'))
        print(' Received from %s:%s' % addr)
        s.sendto(b'Hello,%s!' % data, addr)
    View Code

       客户端

     直接创建Socket 然后与服务器进行数据交换

    import socket
    
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    for data in [b'Hello', b'World']:
        s.sendto(data, ('127.0.0.1', 9999))
        print(s.recv(1024).decode('utf-8'))
    s.close()
    View Code

     分布式简单案例 :其实就是把本地Queue数据网络化,然后一个进程产生taskQueue,另一个处理taskQueue任务并把结果甚至到resultQueue中。

          分布式进程指的是将Process进程分布到多台机器上,充分利用多台机器的性能完成复杂的任务:当做爬虫时,遇到抓取某个网站的所有图片问题

    可以通过设置一个进程抓取所有的连接放在Queue中,另一个进程从Queue中下载所有的图片数据,再保存到resultQueue中??如何实现Queue共享

      分布式过程      

    (1)建立队列Queue,用来进行进程间的通信,服务进程创建队列task_queue,用来作为传递任务给任务进程的通道;服务进程创建队列result_queue,

    作为任务进程任务完成后回复服务进程,可以通过Queuemanager获得Queue接口来添加任务。

    2)把第一步建立的队列在网络上注册,暴露给其他进程,注册后获得网络队列,相当于本地队列的映像

    3)建立一个对象(Queuemanager(BaseManager))实例manager,绑定端口和验证口令。

    4)启动第三步中建立的实例,即启动管理manager,监管信息通道

    5)通过管理实例的方法获得通过网络访问的Queue对象,即再把网络队列实体化成可以使用的本地队列

    6)创建任务到‘本地’队列中,自动上传任务到网络队列中,分配给任务进程处理

      服务器进程代码

    # Linux版本的服务器代码
    
    
    import random, time, queue
    
    from multiprocessing.managers import BaseManager
    
    
    class Queuemanager(BaseManager):
        pass
    # 第一步:建立task_queue 和result_queue,用来存放任务和结果
    result_queue = queue.Queue()
    task_queue = queue.Queue()
    # 第二步:将Queue对象在网络中暴露
    Queuemanager.register('get_task_queue', callable=lambda: task_queue)
    Queuemanager.register('get_result_queue', callable=lambda: result_queue)
    # 第三步:绑定端口8001,设置验证口令'qiye'
    manager = Queuemanager(address=('', 8001), authkey='qiye'.encode())
    # 第四步:启动管理,监听信息通道
    manager.start()
    # 第五步:通过管理实例的方法获得通过网络访问的Queue对象
    task = manager.get_task_queue()
    result = manager.get_result_queue()
    # 第六步:添加任务
    for url in ['ImageUrl_' + i for i in range(10)]:
        print('put task %s...' % url)
        task.put(url)
    # 返回的结果
    print('try get result.....')
    for i in range(10):
        print('result is %s' % result.get(timeout=10))
    manager.shutdown()
    View Code
    # Windows下的服务器代码
    import queue
    from multiprocessing.managers import BaseManager
    from multiprocessing import freeze_support
    
    task_number = 10
    task_queue = queue.Queue(task_number)
    result_queue = queue.Queue(task_number)
    
    
    def get_task():
        return task_queue
    
    
    def get_result():
        return result_queue
    
    
    class QueueManager(BaseManager):
        pass
    
    
    def win_run():
        QueueManager.register('get_result_queue', callable=get_result)
        QueueManager.register('get_task_queue', callable=get_task)
        # 绑定端口并设置验证
        manager = QueueManager(address=('127.0.0.1', 8003), authkey='qiye'.encode())
        manager.start()
        try:
            task = manager.get_task_queue()
            result = manager.get_result_queue()
            for url in ['ImageUrl_%d' % (i) for i in range(task_number)]:
                print('put task %s...' % url)
                task.put(url)
            print('try get result....')
            for i in range(task_number):
                print('result is %s' % result.get(timeout=100))
        except Exception as e:
            print(e)
        finally:
            manager.shutdown()
    if __name__ == '__main__':
        freeze_support();
        win_run()
    View Code

    任务进程

    1)使用QueueManager注册用于获取Queue的方法名称,任务进程只能通过名称在网络上获取Queue

    2)连接服务器,端口和验证口令注意保持与服务器进程中完全一致

    3)从网络上获取Queue,进行本地化

    4)从task队列获取任务,并把结果写入result队列。

    # 任务进程
    import time
    from multiprocessing.managers import BaseManager
    # 创建类似的QueueManager
    class QueueManager(BaseManager):
        pass
    # 第一步:使用QueueManager注册用于获取Queue的方法名称
    QueueManager.register('get_task_queue')
    QueueManager.register('get_result_queue')
    # 连接服务器
    server_addr = '127.0.0.1'
    print('Connect to server %s.....' % server_addr)
    # 端口和验证码口令注意保持与服务器进程完全一致
    m = QueueManager(address=(server_addr, 8003), authkey='qiye'.encode())
    # 网络链接
    m.connect()
    # 第三步:获取Queue的对象
    task = m.get_task_queue()
    result = m.get_result_queue()
    # 第四步:从task队列获取任务,并把结果写入result队列
    while (not task.empty()):
        image_url = task.get(True, timeout=5)
        print('run task downlaod%s....' % image_url)
        time.sleep(1)
        result.put('%s----->success' % image_url)
    print('work exit.')
    View Code

    ·

                         

               

                  

        

         

         

        

           

           

             

             

      

           

           

        

              

         

  • 相关阅读:
    2. C++ continue
    1. Vector
    1007. 行相等的最少多米诺旋转
    4. 寻找两个正序数组的中位数
    3.无重复字符的最长子串
    1. 两数之和
    509. 斐波那契数
    Linux内核源码分析之setup_arch (三)
    1018-可被5整除的二进制前缀
    605-种花问题
  • 原文地址:https://www.cnblogs.com/09120912zhang/p/7601928.html
Copyright © 2020-2023  润新知