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

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

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

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

makefie的简单用法:

#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()
f = 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退出,和异常退出:强制退出。然后观察服务端是否运行正常。

#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 c 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() #阻塞
f = 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 c in self.clients.values():
c.writelines(msg)
c.flush() cs = ChatServer()
print('!!!!!!!!!!!')
cs.start()
print('~~~~~~~~~~~~~~~~~~~~')
e = 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使用。

[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. 三:Bootstrap-js插件

    模式框: <button class="btn btn-default btn-lg" data-toggle="modal" data-target=& ...

  2. 使用webClient实现图片同步,异步下载

    WebClient.DownloadFile 方法 将具有指定 URI 的资源下载到本地文件. 命名空间:System.Net 程序集:System(在 system.dll 中) 同步实现参考代码: ...

  3. Java基础——封装类

    封装类的由来: 为了将基本类型以对象行使存在,java对八个基本类型提供了引用类型,这八个引用类型称为基本类型的“包装类”. 八个基本类型对应的封装类: int           --->   ...

  4. CentOS 安装Parallels Tools

    为了做到Mac和Linux之间共享文件夹,因此需要安装Parallels Tool, 具体安装步骤可以参考 install parallels tool for linux guest http:// ...

  5. MySQL:入门

    一.前言 MySQL :是用于管理数据的软件 MySQL是一种关系数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性. 分为服务端和客户 ...

  6. C++ Knowledge series 1

    Programming language evolves always along with Compiler's evolvement. 1. The C++ Object Model: Strou ...

  7. python学习笔记之——正则表达式

    1.re模块 Python通过re模块提供对正则表达式的支持,re 模块使 Python 语言拥有全部的正则表达式功能.使用re的一般步骤是先将正则表达式的字符串形式编译为Pattern实例,然后使用 ...

  8. Maximum Subarray 连续子数组最大和

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  9. iis7 未注册framework4 导致 莫名的404错误

    server2008  R2 IIS7 已经安装 安装framework 4.6.1 然后建立站点 404错误 :在站点目录自动生成了  asp_client 重新注册到 iis(不需要) iisre ...

  10. Google Developers 中国网站正式发布

    Google Developers 中国网站 (developers.google.cn) 正式发布!Google Developers 中国网站是特别为中国开发者而建立的,它汇集了 Google 为 ...