(转)[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]\t [%(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]\t [%(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} {}:{}\n{}\n" . 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, 10156 2017 / 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, 10156 2017 / 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使用。

转载于:https://www.cnblogs.com/liujiacai/p/10504111.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值