服务端源码

 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: zengchunyun
"""
import socket
import select
import queue
import sys
import time class MyServer(object):
def __init__(self, server_address):
"""
初始化服务器配置
:param server_address:
:return:
"""
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP socket
self.socket.setblocking(False) # 设置非阻塞
self.server_address = server_address # 设置服务器IP端口 self.readlist = [] # 生成可读列表,当有可接收消息时,说明有可连接请求发送消息到此服务器
self.writelist = [] # 生成可写列表,当该队列含有对象时,说明可以向该对象发送消息,
self.message_queue = {} # 生成消息队列字典,以socket:queue.Queue形式存储接收的请求信息
self.recv_buffer = 1024 # 设置接收的缓冲区大小
self.bind() # 服务器绑定IP端口 def bind(self):
"""
绑定服务器IP端口,最大监听5个队列
:return:
"""
self.socket.bind(self.server_address)
sys.stdout.write("starting up on {} port {}\n".format(*self.server_address))
sys.stdout.flush()
self.socket.listen(5)
self.readlist.append(self.socket) # 将服务器socket实例添加到可读事件列表 def serve_forever(self, interval=0.5):
"""
开始轮询事件
:param interval: 轮询超时时间,单位s
:return:
"""
while self.readlist: # 由于绑定服务器端口时已加入元素,所以该条件成立
try:
# 每次都轮询下面事件列表,当有事件触发时,则继续执行,否则一直阻塞,如果设置了超时时间,则超时后,继续执行
readlist, writelist, exceptionlist = select.select(self.readlist, self.writelist, self.readlist, interval)
except ValueError: # 出现该错误 filedescriptor out of range in select(),说明文件句柄已耗尽
time.sleep(10)
continue
if not (readlist, writelist, exceptionlist): # 如果没有事件被触发,三个列表都是空的
continue # 当三个事件列表都没有被触发都为空,则不继续往下执行
for sock in readlist: # 轮询可读列表,开始接收客户端发来对消息
if sock is self.socket:
request, client_address = sock.accept() # 当服务器本身实例可读时,说明有新连接请求接入
sys.stdout.write("new connection from {} port {}\n".format(*client_address))
sys.stdout.flush()
request.setblocking(False) # 设置非阻塞模式
self.readlist.append(request) # 将新的socket连接请求实例加入到可读列表,下次该客户端发送消息时,由select轮询处理
self.message_queue[request] = queue.Queue() # 以socket实例命名生成一个队列实例,存储该客户端发来的消息
else: # 只有之前建立过连接的客户端才不会触发服务器自身的socket对象,即该对象不是服务器自身socket对象,而是新连接生成对的对象
data = sock.recv(self.recv_buffer) # 如果可读事件不等于服务器本身socket实例,则说明有客户端发送消息过来了
if data: # 如果接收到新消息,则说明客户端发送消息过来了
sys.stdout.write("received [{}] from {} port {}\n".format(data, *sock.getpeername()))
sys.stdout.flush()
self.message_queue[sock].put(data) # 将客户端发来的消息放入它对应的队列里
if sock not in self.writelist: # 并且,如果它没有被放进可写列表,则先添加到该列表,然后接下来统一处理该列表
self.writelist.append(sock) # 当收到该客户端消息,不进行立即回复,先加入到可写事件列表
else: # 如果没有消息,说明客户端断开连接了
sys.stdout.write("closing client {} port {}\n".format(*sock.getpeername())) # 由于收到空消息,说明客户端已断开
sys.stdout.flush()
if sock in self.writelist: # 由于客户端断开连接,则需要清除该socket实例,避免发送异常
self.writelist.remove(sock) # 将该客户端从可写列表移除,避免回复客户端时由于断开了,造成阻塞
self.readlist.remove(sock) # 从可读事件列表移除不存在的客户端
sock.close() # 关闭该连接
del self.message_queue[sock] # 删除该客户端的消息队列 for sock in writelist: # 轮询可写列表,该列表仅存储还没有对客户端请求回复的对象
try:
get_msg = self.message_queue[sock].get_nowait() # 开始获取客户端发来的数据,由于数据队列可能为空,避免阻塞使用nowait()方法
except queue.Empty: # 如果队列为空,可能会触发队列空异常,需要处理该异常,避免影响其他客户端连接
sys.stdout.write("queue is empty\n")
sys.stdout.flush()
self.writelist.remove(sock) # 将该客户端从可写事件移除,即不需要对该客户端发送消息了
except KeyError: # 并发时,可能出现此问题
pass
else: # 表示没有异常,则说明获取到队列消息了
sys.stdout.write("beginning send message to client {} port {}\n".format(*sock.getpeername()))
sys.stdout.flush()
sock.send(get_msg) # 直接将用户发来的消息返回给客户端 for sock in exceptionlist: # 轮询异常事件列表
sys.stdout.write("handling exception condition from {} port {}\n".format(*sock.getpeername()))
sys.stdout.flush()
self.readlist.remove(sock) # 移除异常列表对象
if sock in self.writelist: # 由于客户端异常,所以如果还未对客户端回复消息,则不需要再进行回复了,直接移除该客户端
self.writelist.remove(sock)
sock.close() # 关闭该客户端连接
del self.message_queue[sock] # 删除该客户端的消息队列 if __name__ == "__main__":
server = ("0.0.0.0", 9999)
servermq = MyServer(server)
servermq.serve_forever()

客户端源码

 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: zengchunyun
""" import socket
import sys
import threading class MyClient(object):
def __init__(self, server_address):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_address = server_address
self.recv_buffer = 1024
self.connect() def connect(self):
self.socket.connect(self.server_address)
sys.stdout.write("connecting to {} port {}\n".format(*self.socket.getpeername()))
sys.stdout.flush() def client_forever(self, data=b""):
while True:
# data = bytes(input("请输入: "), "utf8")
if type(data) is not bytes:
data = bytes(str(data), "utf8")
self.socket.send(data)
received_data = self.socket.recv(self.recv_buffer)
if received_data:
sys.stdout.write("received {} from {} port {}\n".format(received_data, *self.socket.getpeername()))
sys.stdout.flush()
break
else:
sys.stdout.write("closing socket {} port {}\n".format(*self.socket.getpeername()))
self.socket.close() def run(data):
server = ("127.0.0.1", 9999)
clientmq = MyClient(server)
clientmq.client_forever(data) if __name__ == "__main__":
for i in range(50000):
t = threading.Thread(target=run, args=(i,))
t.start()
print("has been send {} times".format(i))

select应用的更多相关文章

  1. 最全的ORACLE-SQL笔记

    -- 首先,以超级管理员的身份登录oracle sqlplus sys/bjsxt as sysdba --然后,解除对scott用户的锁 alter user scott account unloc ...

  2. Matplotlib数据可视化(6):饼图与箱线图

    In [1]: from matplotlib import pyplot as plt import numpy as np import matplotlib as mpl mpl.rcParam ...

  3. SELECT INTO 和 INSERT INTO SELECT 两种表复制语句

    Insert是T-sql中常用语句,Insert INTO table(field1,field2,...) values(value1,value2,...)这种形式的在应用程序开发中必不可少.但我 ...

  4. select、poll、epoll之间的区别总结

    select.poll.epoll之间的区别总结 05/05. 2014 select,poll,epoll都是IO多路复用的机制.I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪 ...

  5. LINQ to SQL Select查询

    1. 查询所有字段 using (NorthwindEntities context = new NorthwindEntities()) { var order = from n in contex ...

  6. ADO.NET一小记-select top 参数问题

    异常处理汇总-后端系列 http://www.cnblogs.com/dunitian/p/4523006.html 最近使用ADO.NET的时候,发现select top @count xxxx 不 ...

  7. iosselect:一个js picker项目,在H5中实现IOS的select下拉框效果

    具体文档和demo可以访问github:https://github.com/zhoushengmufc/iosselect 移动端浏览器对于select的展示样式是不一致的,ios下是类似原生的pi ...

  8. SQL Server中SELECT会真的阻塞SELECT吗?

    在SQL Server中,我们知道一个SELECT语句执行过程中只会申请一些意向共享锁(IS) 与共享锁(S), 例如我使用SQL Profile跟踪会话86执行SELECT * FROM dbo.T ...

  9. (转载) Linux IO模式及 select、poll、epoll详解

    注:本文是对众多博客的学习和总结,可能存在理解错误.请带着怀疑的眼光,同时如果有错误希望能指出. 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案 ...

  10. 基于select的python聊天室程序

    python网络编程具体参考<python select网络编程详细介绍>. 在python中,select函数是一个对底层操作系统的直接访问的接口.它用来监控sockets.files和 ...

随机推荐

  1. crm 添加用户 编辑用户 公户和私户的展示,公户和私户的转化

    1.添加用户 和编辑可以写在一起 urls.py url(r'^customer_add/', customer.customer_change, name='customer_add'), url( ...

  2. Entity Framework入门教程(12)--- EF进行批量添加/删除

    EF6添加了批量添加/删除实体集合的方法,我们可以使用DbSet.AddRange()方法将实体集合添加到上下文,同时实体集合中的每一个实体的状态都标记为Added,在执行SaveChange()方法 ...

  3. Ubuntu设置和查看环境变量

    设置环境变量的三种方法 1.1 临时设置 export PATH=/home/yan/share/usr/local/arm/3.4.1/bin:$PATH 1.2 当前用户的全局设置 打开~/.ba ...

  4. 抓包工具Charles基本用法

    我们在进行B/S架构的Web项目开发时,在前端页面与后台交互的调试的时候,通常使用在JSP中加入“debugger;”断点,然后使用浏览器的F12开发者工具来查看可能出错的地方的数据.或者使用Http ...

  5. [Android] Android RxJava2+Retrofit2+OkHttp3 的使用(一) --基础篇 Retrofit2 的使用

    本文是 Android RxJava2+Retrofit2+OkHttp3 的使用(一) --基础篇 Retrofit2 的使用 本文的目标是用 Retrofit写一个网络请求: 本文以从获取天气预报 ...

  6. 数据结构Java实现04---树及其相关操作

    首先什么是树结构? 树是一种描述非线性层次关系的数据结构,树是n个数据结点的集合,这些集结点包含一个根节点,根节点下有着互相不交叉的子集合,这些子集合便是根节点的子树. 树的特点 在一个树结构中,有且 ...

  7. [物理学与PDEs]第1章习题11 各向同性导体中电荷分布的指数衰减

    在各向同性的导体中, Ohm 定律具有如下形式: $$\bex {\bf j}=\sigma {\bf E}, \eex$$ 其中 $\sigma$ 称为电导率. 试证在真空中导体的连续性方程为 $$ ...

  8. Karma (Test runner)

    Karma https://baike.baidu.com/item/%E7%BE%AF%E7%A3%A8/7618552?fromtitle=Karma&fromid=878453 1,意译 ...

  9. .net使用Aspose.Words进行Word替换操作的实现代码

    DLL文件下载 示例: Aspose.Words.Document doc = new Aspose.Words.Document(TempFile); Aspose.Words.DocumentBu ...

  10. 出现Failed to get convolution algorithm的解决方法

    当运行卷积神经时出现了问题:Failed to get convolution algorithm. This is probably because cuDNN failed to initiali ...