该程序是处理平时的算数运算,程序也没有什么特别之处,只是将所有运算分开运算,每个函数(线程)处理不同的运算符号里面的运算,然后将所有结果都汇总到main函数中进行最后汇总(相加减)运算,
每个函数内都处理相加减法运算并返回结果给main函数中,然后在main函数将最后的结果返回给用户。可能我是因为不会线程间的通信,所以才想到了这个办法来处理线程间的通信问题。
但是处理效率问题还没有考虑,也没有对比过,所以只能交给大家去测试啦。 程序中主要的代码就是线程中使用socket进行通信,每个函数都启用了socket来作为服务器和客户端,每一个函数都处理不同的部分,如处理的{}里面的运算是使用Curlybraces函数处理,
每个函数都是进行单运算符的运算,如乘法运算函数Multiplication,但只能处理两个数值的乘法运算,如Curlybraces函数只能处理{},如果{}里面有其他的括号([]、())
就不能正常处理里面的括号的运算。 程序的设想图:

图虽然有点简陋,但是还是可以说明问题的。图中对应的符号就是处理相应的运算符的函数,图中的每个函数都不是独立的,而都是通过socket来相连着,每条线都好比是一条网线,
只要是相连着都是可以进行通信的,所以当处理大括号'{}'函数中如果存在除加法和减法外的其他运算符都是可以通过socket通信来获取相应表达式的结果,其他的也亦然。 具体的程序代码如下: 首先,初始化用到的变量和数据,导入相关的库文件。portn的端口是不是感觉与下面的funcPort字典重复了?其实我只是将其分得更细而已,这个portn是各线程创建socket对象和用于监听的端口,
而funcPort字典则是各个线程作为客户端来连接相应处理函数的端口,看下去你就会明白了。
import socket
import threading
import time
import re # 将所有的端口和函数绑定
port1 = 8001 # to deal with {} Curlybraces()
port2 = 8002 # to deal with [] Brackets()
port3 = 8003 # to deal with () Parentheses()
port4 = 8004 # to deal with * Multiplication()
port5 = 8005 # to deal with / Division()
port6 = 8006 # to deal with % TakeMoreThan() host = '127.0.0.1' # 本地IP # 存放所有函数的字典,这样在调用函数时可以通过字典的key来获取相应的函数 funcPort = {'{':'',
'[':'',
'(':'',
'*':'',
'/':'','%':''}

既然要将所有的加法和减法运算都在函数的本身处理,那得想办法将减法和加法融合。刚开始的时候我是再创建一个处理减法的函数,但是如果这样处理的话就导致线程函数内部

更加复杂啦,但是想起最近看过了正则表达式有替换字符的功能,所以想到使用正则表达式去处理这个问题,只需要将表达式的减法转换成加法就可以了,然后在函数本身处理中,

只需以'+'将表达式字符串分成好几块,这样就可以保证函数本身可以处理加法和减法运算了。

def SearchRemoveSub(string):
string_b = re.sub('-','+-',string)
return string_b

但是括号的处理确实有些难度,因为你要判断该括号有没有出现,还要判断其位置,最后将其分成独立的一块,然后将其交给相应的处理函数处理,这个问题也是困扰了我很久,

测试过好多方法,最后还是用上了正则表达式来处理相应括号的搜索并返回一个值来判断该括号是否存在

def SearchParentheses(string):

    num1=num2=num3=0
if re.search('.*\{.*',string):
if re.search('.*\}.*',string):
num1 = 1
else:
# 上面的if语句不能判断输入的 } 在 { 的前面的情况
pass
if re.search('.*\[.*',string):
if re.search('.*\].*',string):
num2 = 2
else:
pass
if re.search('.*\(.*',string):
if re.search('.*\).*',string):
num3 = 3
else:
pass
else:
pass
return num1,num2,num3

这里没有对一些情况进行处理,如:括号只出现一个呢,那应该要返回一个值来判断该括号是不完整的;还不能处理当这些括号在一个表达式中存在多对时也是不行的;

还有就是上面注释的,当一对括号的位置颠倒了也是不能判断出来的。以上的情况中都是在用户输入中可能出现的,我们也是要将其处理的。

既然将所有的括号都处理好了,然后现在就要进行函数的socket通信,来处理相应块的表达式了。在连接函数中用到了我们上面定义的字典,在代码中科院看到这里只是简单的

进行socket通信,主要是将传入的块表达式发送相应函数处理服务器上,然后获取结果。请大家注意的是:要将没有括号的块表达式返回给调用函数中,我之前就是没有这句

return block,然后测试了好久才发现有些值是没有加上去的,导致结果不正确,相信大家应该没有我这么不小心。

def ConnectThread(block):

    for i in block:
if i in ['{','[','(','*','/','%']:
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((host,int(funcPort[i]))) # 通过字典来获取相应的端口
s.sendall(block) # 发送相应结果
result = s.recv(1024)
s.sendall('Done') # 用于告诉服务器该请求连接已结束,以免被连接的服务器线程不知道何时断开连接
s.close()
return result
else:
pass
else:
return block

接下来就是在main函数中调用相应处理的函数了,在这个函数中首先使用SearchRemoveSub函数将传入的表达式进行去除'-',然后使用SearchParentheses函数查找

有可能出现的各种括号,然后通过返回值来判断这些括号有没有出现,一旦出现相应的括号就使用ConnectThread函数连接相应的函数处理,并将结果直接通过正则表达式

替换原来的块表达式,这样保证了最终的string_b处理的都是加法而没有其他运算符的出现。当然这里没有解决一个括号包含或被包含的情况或一个括号包含多种括号或多个

括号的情况,如果有需要的可以改写一下,可以判断每个括号的位置如果有的话,然后比较括号的位置大小,如果有些括号被包含的话,只要稍作判断就可以了,别的就不

多说了。在这段代码的最后使用字符串函数split将整个表达式以'+'分开,然后进行累加,得到整个表达式的和,最后返回给调用函数,即main函数。

def AddAndSub(string):

    string_b = SearchRemoveSub(string)
num1,num2,num3 = SearchParentheses(string_b)
# 只能用于各种括号不互相包含的情况下
if num1 == 1:
try:
# {}存在,查找{}的位置
startCu = string_b.index('{')
endCu = string_b.index('}')
blockCu = string_b[startCu:endCu + 1] # {}数据块 当 startCa > endCa 时会导致捕获不了字符串
# 调用相应处理的函数并捕获返回值
result = ConnectThread(blockCu)
string_b = string_b.replace(blockCu,result)
except ValueError:
# {}这对符号可能只存在一个
print('Error expressions in {}')
else:
pass if num2 == 2:
# 找到[]
try:
startBr = string_b.index('[')
endBr = string_b.index(']')
blockBr = string_b[startBr:endBr + 1]
# 调用相应处理的函数并捕获返回值
result = ConnectThread(blockBr)
string_b = string_b.replace(blockBr,result)
except ValueError:
# []这对符号可能只存在一个
print('Error expressions in []')
else:
pass if num3 == 3:
try:
# ()存在
startPr = string_b.index('(')
endPr = string_b.index(')')
blockPr = string_b[startPr:endPr + 1] # 当 startCa > endCa 时会导致捕获不了字符串
# 调用相应处理的函数并捕获返回值
result = ConnectThread(blockPr)
string_b = string_b.replace(blockPr,result)
except ValueError:
# ()这对符号可能只存在一个
print('Error expressions in ()')
else:
pass data = string_b.split('+') # string_b已将'-'变为'+-'
print('all data :'),
print(data) # 将每个块的值都列举出来,以防出错
print('\nall data sum is :')
Sum = 0
for d in data:
# 接收返回来的值,并将其相加
Sum += float(ConnectThread(d))
print('Sum : ' + str(Sum)) return Sum

然后就是编写相应的处理函数部分了,主要通过socket创建socket对象,并监听相应端口,处理来自客户端的数据,在这些函数中并没有使用多线程去处理,当出现多个客户端

同时连接该服务器时可能会出现socket.error异常。

首先的是单运算符的处理函数,乘法运算函数,从函数可以看出只可以处理两个数值的乘法运算,还有就是不能处理当表达式出现像5*6/3等这种类似的情况,

如果要处理多个值的乘法运算等其他情况那就要改写一下代码啦,在这里我就不多说什么啦,这需要大家去思考一下啦。

def Multiplication():

    q =  True
s4 = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s4.bind((host,port4)) # 绑定IP和端口
s4.listen(5) # 启动监听
while q:
conn,addr = s4.accept() # 重复监听连接请求
# 进入和处理连接请求
while True:
try:
data = conn.recv(1024)
if data == 'quit':
q = False
conn.close()
break # 退出当前循环和退出当前连接
elif data == 'Done':
conn.close()
break
else:
dataValue = data.split('*')
result = float(dataValue[0].strip()) * float(dataValue[1].strip()) # 只处理两个值相乘?
conn.sendall(str(result))
except socket.error,e:
print('Multiplication is Error',e)
q = False
break
s4.close()

至于除法运算和取余等其他的运算也是和乘法运算大同小异,只需要稍微修改一下乘法的代码就行拉,这里就不一一列举出来啦。

然后就是各个括号的处理函数了,首先是大括号{}处理的函数,在这个函数中主要是监听相应的端口,接收来自客户端的数据,通过'+'将传入的表达式分成几个块,

然后通过ConnectThread来调用处理块表达式获取到返回的结果,再在本地进行累加,然后将累加的结果再发送回客户端中。这个过程就像是上述的AddAndSub一样。

def Curlybraces():

    q =  True
s1 = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s1.bind((host,port1)) # 绑定IP和端口
s1.listen(5) # 启动监听
start = 0 # '{' 字符的位置
end = 0 # '}' 字符的位置
conn,addr = s1.accept()
while q:
try:
data = conn.recv(1024) # 接收数据
if data == 'quit':
q = False
else:
try:
start = data.index('{')
end = data.index('}')
exist = True # 查找符号存在
except ValueError:
#print('Ca va error')
exist = False # 查找符号不存在或个别不存在
if exist:
# 如果存在,就将该字符去掉,在计算其里面的算数
print('get in Curlybraces')
Sum = 0 # 和
block = data[start + 1:end]
blockData = block.split('+')
for d in blockData:
Sum += float(ConnectThread(d))
print('Sum : ' + str(Sum))
conn.sendall(str(Sum)) # 发送结果
print('quit Curlybraces')
except socket.error,e:
#print('Ca error')
print(str(e).decode('gb2312'))
q = False # 关闭该线程
s1.close()

然后就是[]和()这两个括号的处理了,当然大家参照上述处理{}括号的函数就可以简单的写出来了,也没有什么特别的难的地方,都是类似的,所以就不将其一一粘贴出来了,

最后就是main函数的编写了,在该函数中主要是创建函数线程和启动所有的函数线程,大家可以发现,这个函数中只能计算一次的表达式后就不会再有输入了,不过大家可以

循环AddAndSub函数就可以计算多次输入的表达式了,如果出错也是需要大家自己去寻找解决方案的。本人在测试过程中也是出现很多的错误,但是还是一个个的解决了,

所以当出现错误时,不要惊慌,使用print来排查是那一块出现错误,哪一块不能执行导致出现错误。当然由于能力有限,在测试中我尝试使用for循环来创建和启动所有线程时

就出现了错误,但是不是因为其他函数出现错误,所以正如大家所见的代码都是一句句代码将一个个的线程启动起来的。

def main(string_all):

    start = time.time()   # 启动时间
print('start all threading') # 创建并启动所有函数线程
# 将函数与编号关联,可以使用循环来创建和启动线程
thread1 = threading.Thread(target=Curlybraces)
thread1.start()
thread2 = threading.Thread(target=Brackets)
thread2.start()
thread3 = threading.Thread(target=Parentheses)
thread3.start()
thread4 = threading.Thread(target=Multiplication)
thread4.start()
thread5 = threading.Thread(target=Division)
thread5.start() result = AddAndSub(string_all) print('result : ' + str(result)) print('use time : ' + str(time.time() - start)) # 整个过程所需的时间 # 等待线程的终止
# 应该放到程序的后面,不然会导致程序运行停止在
# 监听线程结束的信号中,不会执行下去
thread1.join()
thread2.join()
thread3.join()
thread4.join()
thread5.join()

接下来就到了激奋人心的时刻了,测试代码的运行,测试代码很简单,只需要调用main函数就可以啦:

if __name__ == '__main__':
main('1+2+3+4+5+{1+2+3+4+4*4+4/2+10-5}+[44+342+3423]+(3424+234-213)')

测试结果如下:

start all threading
get in Curlybraces
Sum : 1.0
Sum : 3.0
Sum : 6.0
Sum : 10.0
Sum : 26.0
Sum : 28.0
Sum : 38.0
Sum : 33.0
quit Curlybraces
get in Brackets
Sum : 44.0
Sum : 386.0
Sum : 3809.0
quit Brackets
get in Parentheses
Sum : 3424.0
Sum : 3658.0
Sum : 3445.0
quit Parentheses
all data : ['1', '2', '3', '4', '5', '33.0', '3809.0', '3445.0']

all data sum is :
Sum : 1.0
Sum : 3.0
Sum : 6.0
Sum : 10.0
Sum : 15.0
Sum : 48.0
Sum : 3857.0
Sum : 7302.0
result : 7302.0
use time : 0.0269999504089

不相信这结果的博友们可以认证一下喔,反正我信啦。整个程序大致就是这样啦,虽然问题挺多且没有解决的,但也算是一个完整的程序啊,这个程序的意义不大,但是由于是

自己的突发奇想,然后就想分享一下,但是每个人的看法和理解都不一样,也不知道大家能不能明白,也不知道各路大神有什么看法,但请不要喷        谢谢。

这个程序完全是个人的一些想法,由于看到了太多不一样的东西,自己也就想写一个不一样的东西,仅此而已。但是大家可以尝试一下将所有的处理函数,运行到不一样的主机

上,然后只需要修改一下连接的IP地址即可,或者可以将该想法应用到不一样的程序中,来达到自己想要的效果,至于可以应用到什么样的程序中,那有待大家去开发,但是我

觉得可以应用到运算方面的程序和处理数据的程序上,由于个人的知识有限,也不知道有哪一项技术是与这些相关的,the end ...

<div style="border:silver 1px dashed;background-color: rgba(0, 0, 0, 0);width:600px;padding:12px;font-size: 12px;font-family: 微软雅黑; ">
作者:<a href="http://www.cnblogs.com/GHost-Ma/" target="_blank">sdjnzqr</a><br>
出处:<a href="http://www.cnblogs.com/GHost-Ma/">http://www.cnblogs.com/GHost-Ma/</a><br>
版权:本文版权归作者和博客园共有<br>
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
</div>

线程间使用socket通信的计算器的更多相关文章

  1. iOS开发之线程间的MachPort通信与子线程中的Notification转发

    如题,今天的博客我们就来记录一下iOS开发中使用MachPort来实现线程间的通信,然后使用该知识点来转发子线程中所发出的Notification.简单的说,MachPort的工作方式其实是将NSMa ...

  2. linux c 线程间同步(通信)的几种方法--互斥锁,条件变量,信号量,读写锁

    Linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量.信号量和读写锁. 下面是思维导图:  一.互斥锁(mutex)  锁机制是同一时刻只允许一个线程执行一个关键部分的代码. 1 . ...

  3. JUC之线程间定制化通信

    线程通信之定制化 之前文章中写了下Condition的使用,这里我们详细说下其中的用法: 首先使用Condition需要实例化Lock private Lock lock = new Reentran ...

  4. rtt学习之线程间同步与通信

    一 线程间的同步与互斥:信号量.互斥量.实践集 线程互斥是指对于临界区资源访问的排它性,如多个线程对共享内存资源的访问,生产消费型对产品的操作.临界区操作操作方法有: rt_hw_interrupt_ ...

  5. 线程间通过PostMessage通信

    1.查看TMS项目中的相关实例 ::PostMessage(hWnd, WM_USER_MSG_REFRESH_UI, (WPARAM)UMP_REFRESH_MEMBER_INFO, 0); 参考文 ...

  6. Java多线程编程核心技术---线程间通信(二)

    通过管道进行线程间通信:字节流 Java提供了各种各样的输入/输出流Stream可以很方便地对数据进行操作,其中管道流(pipeStream)是一种特殊的流,用于在不同线程间直接传送数据,一个线程发送 ...

  7. C++多线程编程(三)线程间通信

    多线程编程之三——线程间通讯 作者:韩耀旭 原文地址:http://www.vckbase.com/document/viewdoc/?id=1707 七.线程间通讯 一般而言,应用程序中的一个次要线 ...

  8. wait/notify实现线程间的通信

    使线程之间进行通信之后,系统间的交互性更加强大,在大大提高CPU利用率的同时还会使程序对各线程任务在处理的过程中进行有效的把控与监督. 1.不使用wait/notify实现线程间通信 使用sleep( ...

  9. Java多线程编程(三)线程间通信

    线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时 ...

随机推荐

  1. easyui combo自动高度(下拉框空白问题)

    设置.combo-panel {max-height:200px;} 在用到easyui-combobox时,设置panelHeight:'auto'

  2. zoj1027 Human Gene Functions

    一道动态规划,两个串进行匹配,不同字母匹配的值不一样,也可以和空格匹配(空格不能与空格匹配),求最大的匹配值. 数据很弱,每个串都在100以内. 定义dp[i][j]为第一个串前i个数和第二个串前j个 ...

  3. oracle中的初始化参数文件

    oracle初始化参数文件管理 oracle实例是指运行状态下的oracle软件,是由内存结构跟一些进程结构组成的,主要实现数据库的访问跟控制功能,是oracle的核心. 初始化参数文件是oracle ...

  4. linux 生产环境搭建

    Linux基础命令杂记   今天又一次搞Linux生产环境搭建.这是种步骤很多,很繁琐而且又不得不做的事情.虽然做过很多次,但还是有很多步骤.命令不记得,每一次到处找资料很麻烦,于是将一些步骤记下,以 ...

  5. Laravel中的队列处理

    Laravel中的队列处理 队列介绍 为什么要有消息队?这里先对其进行一个简单的介绍,方便还不了解的同学理解.在面向对象里,有一个很简单的概念--消息传递,而消息队列就可以在它上面扩展一下,把它说的更 ...

  6. Maven管理Android项目1

    maven-android-plugin网站:https://code.google.com/p/maven-android-plugin/wiki/GettingStarted   android ...

  7. C++ Primer第四版 15.9 再谈文本查询 程序实现

    编程过程中发现书本中的示例程序并不完全,某些地方存在错误,现已改正并添加少许注释.. 1 #include<iostream> 2 #include<fstream> #inc ...

  8. 在ubuntu10.0.4下更新git

    今天想到要在ubuntu10.0.4下下载android的源码学习一下.源码下载用到了git.以前安装过git以为应该没什么问题的,没想到报了 “fatal: git 1.7.2 or later r ...

  9. 最全面 Nginx 入门教程 + 常用配置解析

    转自 http://blog.csdn.net/shootyou/article/details/6093562 Nginx介绍和安装 一个简单的配置文件 模块介绍 常用场景配置 进阶内容 参考资料 ...

  10. Android AndroidManifest 清单文件以及权限详解!【转】

    转自:http://my.oschina.net/yuanxulong/blog/366753 每个Android应用都需要一个名为AndroidManifest.xml的程序清单文件,这个清单文件名 ...