zoukankan      html  css  js  c++  java
  • (转)[Python 网络编程] makefile (三)

    socket.makefile(mode ='r',buffering = None,*,encoding = None,errors = None,newline = None )
    返回一个与套接字相关联的文件对象。返回的确切类型取决于给makefile()提供的参数。

    这些参数的解释方式与内置open()函数的解释方式相同,除了makefile方法唯一支持的mode值是'r'(默认)'w'和'b'。

    套接字必须处于阻塞模式; 它可能有超时,但是如果超时发生,文件对象的内部缓冲区可能会以不一致的状态结束。

    关闭返回的文件对象makefile()将不会关闭原始套接字,除非所有其他文件对象已关闭并且 socket.close()已在套接字对象上调用。

     makefie的简单用法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    #makefile
    import threading,logging,socket
    DATEFMT="%H:%M:%S"
    FORMAT = "[%(asctime)s] [%(threadName)s,%(thread)d] %(message)s"
    logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT)
     
    sock = socket.socket()
    addr = ('127.0.0.1',9999)
    event = threading.Event()
     
    sock.bind(addr)
    sock.listen()
     
    def _accept(sock:socket.socket):
        s,addrinfo = sock.accept()
        = s.makefile(mode='rw')
     
        while True:
            line = f.readline() # read(10) 文本使用readline
            logging.info(line)
     
            if line.strip() == 'quit':
                break
     
            msg = "Your msg = {}. ack".format(line)
            f.write(msg)
            f.flush()
        f.close()
        sock.close()
     
     
    threading.Thread(target=_accept,args=(sock,)).start()
     
    while not event.wait(2):
        logging.info(sock)
     
     
    #运行结果:
    [19:09:47]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:09:49]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:09:49]   [Thread-1,6044] hi?
     
    [19:09:51]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:09:53]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:09:55]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:09:57]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:09:59]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:10:01]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:10:03]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:10:05]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:10:07]   [Thread-1,6044] Are you ok?
     
    [19:10:07]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:10:09]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:10:11]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:10:13]   [MainThread,3544] <socket.socket fd=288, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999)>
    [19:10:13]   [Thread-1,6044] quit
     
    [19:10:15]   [MainThread,3544] <socket.socket [closed] fd=-1, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0>

      

    TCP Server 改装成makefile:

    连接两个客户端分别测试消息是否分发正常,客户端quit指令是否可以正常关闭socket,self.clients字典是否已经移除失联的socket。

    客户端分别测试正常退出:quit退出,和异常退出:强制退出。然后观察服务端是否运行正常。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    #TCP Server 改装成makefile
    import threading,logging,time,random,datetime,socket
    DATEFMT="%H:%M:%S"
    FORMAT = "[%(asctime)s] [%(threadName)s,%(thread)d] %(message)s"
    logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT)
     
    class ChatServer:
        def __init__(self,ip='127.0.0.1',port=9999): #启动服务
            self.addr = (ip,port)
            self.sock = socket.socket()
            self.event = threading.Event()
     
            self.clients = {} #客户端
     
        def show_client(self):
            while not self.event.is_set():
                if len(self.clients) > 0:
                    logging.info(self.clients)
                    self.event.wait(3)
     
     
        def start(self):
            self.sock.bind(self.addr)
            self.sock.listen()
            # accept会阻塞主线程,所以开一个新线程
            threading.Thread(target=self._accept,name='accept',daemon=True).start()
            threading.Thread(target=self.show_client,name='show_client',daemon=True).start()
     
     
        def stop(self):
            for in self.clients.values():
                c.close()
            self.sock.close()
            self.event.wait(3)
            self.event.set()
     
        def _accept(self):
            while not self.event.is_set(): #多人连接
                conn,client = self.sock.accept()  #阻塞
                = conn.makefile(mode='rw',encoding='utf8')
                self.clients[client] = f
     
                logging.info("{}-{}".format(conn,client))
                # recv 默认阻塞,每一个连接单独起一个recv线程准备接收数据
                threading.Thread(target=self._recv, args=(f, client), name='recv',daemon=True).start()
     
        def _recv(self, f, client): #接收客户端数据
            while not self.event.is_set():
                try:
                    data = f.readline()
                except Exception:
                    data = 'quit'
                finally:
                    msg = data.strip()
                    # Client通知退出机制
                    if msg == 'quit':
                        f.close()
                        self.clients.pop(client)
     
                        logging.info('{} quit'.format(client))
                        break
     
                msg = "{:%Y/%m/%d %H:%M:%S} {}:{} {} ".format(datetime.datetime.now(),*client,data)
                print(msg)
                logging.info(msg)
     
                for in self.clients.values():
                    c.writelines(msg)
                    c.flush()
     
     
     
    cs = ChatServer()
    print('!!!!!!!!!!!')
    cs.start()
    print('~~~~~~~~~~~~~~~~~~~~')
    = threading.Event()
    def showthreads(e:threading.Event):
        while not e.wait(3):
            logging.info(threading.enumerate())
     
    threading.Thread(target=showthreads,name='showthreads',args=(e,)).start()
     
    while not e.wait(1): # Sever控制台退出方式
        cmd = input('>>> ').strip()
        if cmd == 'quit':
            cs.stop()
            e.wait(3)
            break
     
    #运行结果:
    !!!!!!!!!!!
    ~~~~~~~~~~~~~~~~~~~~
    >>> [15:18:49]  [show_client,4284] {('127.0.0.1'3507): <_io.TextIOWrapper mode='rw' encoding='utf8'>}
    [15:18:49]   [accept,2820] <socket.socket fd=388, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1'9999), raddr=('127.0.0.1'3507)>-('127.0.0.1'3507)
    [15:18:49]   [showthreads,8384] [<Thread(showthreads, started 8384)>, <Thread(accept, started daemon 2820)>, <Thread(show_client, started daemon 4284)>, <_MainThread(MainThread, started 932)>, <Thread(recv, started daemon 10156)>]
    [15:18:52]   [show_client,4284] {('127.0.0.1'3507): <_io.TextIOWrapper mode='rw' encoding='utf8'>}
    [15:18:52]   [showthreads,8384] [<Thread(showthreads, started 8384)>, <Thread(accept, started daemon 2820)>, <Thread(show_client, started daemon 4284)>, <_MainThread(MainThread, started 932)>, <Thread(recv, started daemon 10156)>]
    [15:18:54]   [recv,101562017/12/24 15:18:54 127.0.0.1:3507
    2017/12/24 15:18:54 127.0.0.1:3507
    123
    123
     
     
     
     
    [15:18:55]   [show_client,4284] {('127.0.0.1'3507): <_io.TextIOWrapper mode='rw' encoding='utf8'>}
    [15:18:55]   [showthreads,8384] [<Thread(showthreads, started 8384)>, <Thread(accept, started daemon 2820)>, <Thread(show_client, started daemon 4284)>, <_MainThread(MainThread, started 932)>, <Thread(recv, started daemon 10156)>]
    [15:18:58]   [show_client,4284] {('127.0.0.1'3507): <_io.TextIOWrapper mode='rw' encoding='utf8'>}
    [15:18:58]   [showthreads,8384] [<Thread(showthreads, started 8384)>, <Thread(accept, started daemon 2820)>, <Thread(show_client, started daemon 4284)>, <_MainThread(MainThread, started 932)>, <Thread(recv, started daemon 10156)>]
    [15:19:01]   [show_client,4284] {('127.0.0.1'3507): <_io.TextIOWrapper mode='rw' encoding='utf8'>}
    [15:19:01]   [showthreads,8384] [<Thread(showthreads, started 8384)>, <Thread(accept, started daemon 2820)>, <Thread(show_client, started daemon 4284)>, <_MainThread(MainThread, started 932)>, <Thread(recv, started daemon 10156)>]
    [15:19:04]   [show_client,4284] {('127.0.0.1'3507): <_io.TextIOWrapper mode='rw' encoding='utf8'>}
    [15:19:04]   [showthreads,8384] [<Thread(showthreads, started 8384)>, <Thread(accept, started daemon 2820)>, <Thread(show_client, started daemon 4284)>, <_MainThread(MainThread, started 932)>, <Thread(recv, started daemon 10156)>]
    [15:19:07]   [show_client,4284] {('127.0.0.1'3507): <_io.TextIOWrapper mode='rw' encoding='utf8'>}
    [15:19:07]   [showthreads,8384] [<Thread(showthreads, started 8384)>, <Thread(accept, started daemon 2820)>, <Thread(show_client, started daemon 4284)>, <_MainThread(MainThread, started 932)>, <Thread(recv, started daemon 10156)>]
    [15:19:10]   [show_client,4284] {('127.0.0.1'3507): <_io.TextIOWrapper mode='rw' encoding='utf8'>}
    [15:19:10]   [showthreads,8384] [<Thread(showthreads, started 8384)>, <Thread(accept, started daemon 2820)>, <Thread(show_client, started daemon 4284)>, <_MainThread(MainThread, started 932)>, <Thread(recv, started daemon 10156)>]
    [15:19:12]   [recv,101562017/12/24 15:19:12 127.0.0.1:3507
     
     
    [15:19:12]   [recv,10156] ('127.0.0.1'3507) quit
    2017/12/24 15:19:12 127.0.0.1:3507
     
     
    [15:19:13]   [showthreads,8384] [<Thread(showthreads, started 8384)>, <Thread(accept, started daemon 2820)>, <Thread(show_client, started daemon 4284)>, <_MainThread(MainThread, started 932)>]

      

    总结:

    使用makefile返回一个套接字相关联的文件对象,对该文件对象的操作方法,与普通文件操作方法一致,read,readline,write,writeline

    makefile不仅仅可以对accept建立连接后的socketObject使用,也可对主线程的sock和任何socketObject使用。

  • 相关阅读:
    1212321
    123123
    好好干活
    VXLAN学习之路-结合VRF在Linux中实践VXLAN网络
    123456
    期望
    123456
    123456
    Jenkins管理员密码忘记修改操作
    Jenkins 安装与部署详细教程
  • 原文地址:https://www.cnblogs.com/liujiacai/p/10504111.html
Copyright © 2011-2022 走看看