被一个猴子(monkey)折腾了一晚上

版权声明:转载请声明出处Catalog Spri https://blog.csdn.net/qq_33404767/article/details/84038316

事情起因是这样的:
今天学习了单线程实现并发操作,学习了gevent第三方包(周末会更新并发编程知识点,里面会有详细介绍)

老师今天布置了一个作业,其中有一道题目是这样的:

  • 使用协程完成TCP套接字编程 支持多客户端同时访问
    然后我就开始写代码,写完了就报错了

错误代码示例:

# 因为是测试代码,所以写的没有很规范,望见谅
'''
使用协程完成TCP套接字编程 支持多客户端同时访问
'''
# 服务端
import gevent
from gevent import monkey
from socket import *

monkey.patch_all()

server = socket(AF_INET, SOCK_STREAM)

server.bind(('localhost', 9989))

server.listen(5)


def communication(conn):
    while True:
        print("00000")
        data = conn.recv(1024)
        print('asd')
        conn.send(data.upper())


while True:
    conn, addr = server.accept()
    print('新客户端连入', addr)
    g = gevent.spawn(communication, conn)

# 客户端
from socket import *

client = socket(AF_INET, SOCK_STREAM)

client.connect(('localhost', 9989))

while True:
    msg = input('>>:').strip()
    client.send(msg.encode('utf-8'))
    data = client.recv(2014)
    print(data.decode('utf-8'))

代码看起来是没有任何问题的,但是就是无法实现并发执行的效果,很郁闷,纠结了一个晚上,和老师讨论什么的,都没有找到错误点在哪里。

我们讨论完,也没有个结果,老师回去以后用他的电脑也写了一份,代码只有一点点的差距
正确示例:

'''
使用协程完成TCP套接字编程 支持多客户端同时访问
'''
# 服务端
import gevent
import gevent.monkey
gevent.monkey.patch_all()

from socket import *
server = socket()

# 这是为了实现端口重用的代码。当程序不正常结束时,端口可能还没有被操作系统回收,就会导致需要手动更改绑定端口号,测试时候使用!
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)

server.bind(("127.0.0.1",9898))
server.listen(5)


def data_handler(conn,addr):
    while True:
        data = conn.recv(1024)
        print("来自%s : %s" % (addr[1],data.decode("utf-8")))
        conn.send(data.upper())


while True:
    con,addr = server.accept()
    g = gevent.spawn(data_handler,con,addr)
    print("新连接")

我就在拿我的代码和老师的代码作对比,发现只有monkey的位置不同,一开始我根本没想到,monkey的位置会导致代码运行效果完全不同。

然后我就试着把我的monkey位置调动了一下,神奇的事情发生了,代码运行成功了,单线程下并发效果实现了!

错误原因:猴子补丁其实是做替换来的,gvent中有第三方的socket是修改过的不再是以前的那个socket了,只是把使用方法做的和原生的一模一样 。

举个例子:monkey就好比一个装饰器,会把下面的一些东西给偷梁换柱,你以为你在用的是你认识的那个socket,其实已经变成了被装饰过的socket。

  • 装饰器:在不改变函数源代码及调用方式的情况下,为函数增加新功能

monkey装饰的模块

我们看图片中,值为True的都会被猴子给装饰一下。
猴子一定要放在导入模块的前面!!!
大家一定要注意这个问题,避免掉坑。
这个坑困扰了我一晚上,希望能给各位带来解决方法不再困扰你们。

猜你喜欢

转载自blog.csdn.net/qq_33404767/article/details/84038316