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. sql sever 执行较大的文件脚本

    1.用管理员身份打开cmd工具 2.执行命令 osql -S  localhost -U sa -P 123456 -i D:/test.sql -S 服务器地址  本地可简写 . -U 用户名 -P ...

  2. 四、spark集群架构

    spark集群架构官方文档:http://spark.apache.org/docs/latest/cluster-overview.html 集群架构 我们先看这张图 这张图把spark架构拆分成了 ...

  3. MySQL:SQL进阶

    一.数据库相关理论 1.系统数据库 information_schema: 虚拟库,不占用磁盘空间,存储的是数据库启动后的一些参数,如用户表信息.列信息.权限信息.字符信息等performance_s ...

  4. bootstrap框架怎么在html页面加载使用

    今天敲代码的时候,正好碰到这个问题. 与大家分享这个解决方法:     1/7 到bootstrap官方网站下载,对于我们开发者来说,直接下载编译和压缩后的CSS.JavaScript文件,另外还包含 ...

  5. java多线程中的死锁、活锁、饥饿、无锁都是什么鬼?

    死锁.活锁.饥饿是关于多线程是否活跃出现的运行阻塞障碍问题,如果线程出现了这三种情况,即线程不再活跃,不能再正常地执行下去了. 死锁 死锁是多线程中最差的一种情况,多个线程相互占用对方的资源的锁,而又 ...

  6. GIS平台结构设计

    前言: WebGIS由于技术发展和功能定位的原因,一般在进行架构设计的时候更多地考虑是否容易实现.用户交互.数据传输方便.渲染效果等方面,对强GIS的应用考虑得少,所以架构上与桌面的GIS平台很不一样 ...

  7. 浅谈 Underscore.js 中 _.throttle 和 _.debounce 的差异[转]

    看的文章来自: https://blog.coding.net/blog/the-difference-between-throttle-and-debounce-in-underscorejs 使用 ...

  8. 用Java开发贪吃蛇游戏

    贪吃蛇游戏的设计步骤: Part 1: 设计游戏图纸 画出900*700的白色窗口 在窗口上添加画布 在画布上添加标题 在画布上添加黑色游戏区 Part 2: 放置静态的蛇:一个头.两个身体 加上开始 ...

  9. Remove Duplicates from Sorted List 去除链表中重复值节点

    Given a sorted linked list, delete all duplicates such that each element appear only once. For examp ...

  10. AndroidStudio中logcat不输出信息

    2017年11月27日,记住这个日子.今天第一次感觉到被批评了,由于自己技术知识储备不足导致今天的外出工作等于浪费时间.正式因为这个logcat不输出信息的问题,前几回不输出信息了我就从新启动了开发工 ...