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,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使用。

(转)[Python 网络编程] makefile (三)的更多相关文章

  1. [Python 网络编程] makefile (三)

    socket.makefile(mode ='r',buffering = None,*,encoding = None,errors = None,newline = None )返回一个与套接字相 ...

  2. python网络编程【三】(网络服务器)

    建立一个服务器需要以下4步: 1.建立socket对象. 2.设置socket选项(可选的) 3.绑定到一个端口(同样,也可以是一个指定的网卡). 4.侦听连接. 下面代码片段可以实现这些功能: ho ...

  3. python 网络编程(三)---TCP 服务器端客户端实现

    客户端 客户端主要有4个步骤: 1)创建一个socket以连接服务器. socket = socket.socket(family, type),family参数代表地址家族,可为AF_INET(包括 ...

  4. python 网络编程第三版

    为服务端增加多线程解决方案 1.服务端代码如下: ***这个版本并没有真正的起到多线程的作用,主要原因在于t.join():以后的版本会改进这个问题*** #!/usr/bin/python #!co ...

  5. 第十一章:Python の 网络编程基础(三)

    本課主題 多线程的创建和使用 消息队列的介绍 Python 操作 memached 和 redis 实战 本周作业 消息队列的介绍 对列是在内存中创建的,如果整个进程里的程序运行完毕之后会被清空,消息 ...

  6. python网络编程(三)

    udp网络通信过程 udp应用:echo服务器 参考代码 #coding=utf-8 from socket import * #1. 创建套接字 udpSocket = socket(AF_INET ...

  7. 28、Python网络编程

    一.基于TCP协议的socket套接字编程 1.套接字工作流程 先从服务器端说起.服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客 ...

  8. 图解Python网络编程

    返回目录 本篇索引 (1)基本原理 (2)socket模块 (3)select模块 (4)asyncore模块 (5)asynchat模块 (6)socketserver模块 (1)基本原理 本篇指的 ...

  9. Python 网络编程(二)

    Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...

随机推荐

  1. Nginx浅谈

    Nginx的产生 没有听过Nginx?那么一定听过它的"同行"Apache吧!Nginx同Apache一样都是一种WEB服务器.基于REST架构风格,以统一资源描述符(Unifor ...

  2. Asp.net Zero 应用实战-最初部署问题

    此时用的是aspnet-zero-core-4.3.0 1.前两天vs2017刚刚最新升级了,打开后就报错,然后就根据提示把每个项目文件中添加了 <PropertyGroup> <E ...

  3. Lucene学习笔记:基础

    Lucence是Apache的一个全文检索引擎工具包.可以将采集的数据存储到索引库中,然后在根据查询条件从索引库中取出结果.索引库可以存在内存中或者存在硬盘上. 本文主要是参考了这篇博客进行学习的,原 ...

  4. 《Miracle-House团队》项目需求分析改进

    (一)团队项目需求分析改进 一.<西小餐项目需求规格说明书>的不足 通过老师和其他同学的指正和建议,我们发现上次的需求规格说明书存在以下不足: 1.需求规格文档不够完整和规范: 2.系统设 ...

  5. WCF调错方法

    1.在VS cmd里,输入wcftestclient.exe 2.添加Service服务. 3.点击要测试的方法,输入参数,点击Invoke. 4.如果错误信息很模糊,则修改WCF程序所在的Web.c ...

  6. mac系统 pip3 install scrapy 失败 No local packages or working download links found for incremental>=16.10.1

    使用pip3 install scrapy命令之后,会出现如下问题: Collecting scrapy Downloading Scrapy-1.4.0-py2.py3-none-any.whl ( ...

  7. linux 环境统配

    #java JAVA_HOME=/opt/jdk CLASSPATH=$JAVA_HOME/lib/ PATH=$PATH:$JAVA_HOME/bin export PATH JAVA_HOME C ...

  8. 华为云服务器为Tomcat配置SSL

    近期由于开发小程序需要在云服务器上配置https访问协议,也遇到了一点小问题,把配置过程记录一下:SSL 证书申请下来之后会有 .jks .crt .pfx .pem为后缀的文件(如何申请SSL证书这 ...

  9. alfred3配置

    搜索功能配置 github https://github.com/search?utf8=%E2%9C%93&q={query} github'{query}' g baidu http:// ...

  10. kubernetes1.7.6 ha高可用部署

    写在前面:  1. 该文章部署方式为二进制部署. 2. 版本信息 k8s 1.7.6,etcd 3.2.9 3. 高可用部分 etcd做高可用集群.kube-apiserver 为无状态服务使用hap ...