一.接着上一篇文章,实现了客户端和服务器端通讯,那么,客户端与客户端之间可以相互发送消息吗,大学的时候记得有个c语言项目是这样实现的:客户端和服务器端之间用tcp连接并记录客户端ip和端口号,客户端和客户端用udp连接发送消息(客户端ip和端口号从服务器端获取)。

今天试下利用队列实现客户端和客户端发送消息。
    原理:多个客户端同时在线,服务器端会产生多个线程,那么这些线程之间可以利用队列Queue实现相互发送消息。

二. 先看下队列怎么使用,如下代码:queue_test.py

from queue import Queue
from threading import Thread
import time

class Student(Thread):
    def __init__(self, name, queue):
        super().__init__()
        self.name = name
        self.queue = queue

    def run(self):
        while True:
            # 阻塞程序,时刻监听老师,接收消息
            msg = self.queue.get()
            # 一旦发现点到自己名字,就赶紧答到
            if msg == self.name:
                print("{}:到!".format(self.name))
            else:
                pass
                #self.queue.put(msg)


class Teacher:
    def __init__(self, queue):
        self.queue=queue

    def call(self, student_name):
        print("老师:{}来了没?".format(student_name))
        # 发送消息,要点谁的名
        self.queue.put(student_name)

if __name__ == "__main__":
    
    queue = Queue()
    teacher = Teacher(queue=queue)
    s1 = Student(name="小明", queue=queue)
    s2 = Student(name="小亮", queue=queue)
    s1.start()
    s2.start()

    print('开始点名~')
    teacher.call('小明')
    time.sleep(1)
    teacher.call('小亮')
    time.sleep(1)
    teacher.call('小明')
    time.sleep(1)

运行结果如下:

python线程之间传递数据 python线程间通讯_python线程之间传递数据


代码中将两个线程加到队列中,

s1 = Student(name=“小明”, queue=queue)
 s2 = Student(name=“小亮”, queue=queue)注意这个顺序对于后面的调用非常重要。

为了效果我们把 开始点名那个地方代码替换下面的代码:

print('开始点名~')
	teacher.call('小亮')
    time.sleep(1)
	teacher.call('小明')
    time.sleep(1)
    teacher.call('小亮')
    time.sleep(1)

运行结果如下:

python线程之间传递数据 python线程间通讯_python线程之间传递数据_02


结果中却没有出现学生喊到,为什么呢,没错,因为队列,小明的线程排在第一个,所有不管老师喊谁,小明第一个取数据发现不是自己不打印到,接着小亮,再小明…这样就会出现上面老师点名没有一个学生到。我们可以做个小修改,在小明一个取数据发现不是自己的时候,将数据重新放到队列中,让其他人取。

student类中添加else如下:

# 一旦发现点到自己名字,就赶紧答到
            if msg == self.name:
                print("{}:到!".format(self.name))
            else:
                self.queue.put(msg)

结果如下:

python线程之间传递数据 python线程间通讯_python_03


思考,如果点名不在这个队列中,如小花,会怎样呢。当然会导致代码出现死循环

修改queue_test.py代码如下:

from queue import Queue
from threading import Thread
import time

all_student = list()

class Student(Thread):
    global all_student
    def __init__(self, name, queue):
        super().__init__()
        self.name = name
        self.queue = queue
        all_student.append(name)
    def run(self):
        while True:
            # 阻塞程序,时刻监听老师,接收消息
            msg = self.queue.get()
            # 一旦发现点到自己名字,就赶紧答到
            if msg == self.name:
                print("{}:到!".format(self.name))
            else:
                
                if all_student.__contains__(msg):
                    print(msg)
                    self.queue.put(msg)
                    time.sleep(0.001)


class Teacher:
    def __init__(self, queue):
        self.queue=queue

    def call(self, student_name):
        print("老师:{}来了没?".format(student_name))
        # 发送消息,要点谁的名
        self.queue.put(student_name)
def main():
    queue = Queue()
    teacher = Teacher(queue=queue)
    s1 = Student(name="小明", queue=queue)
    s2 = Student(name="小亮", queue=queue)
    s1.start()
    s2.start()

    print('开始点名~')
    teacher.call('小话')
    time.sleep(1)
    teacher.call('小亮')
    time.sleep(1)
    teacher.call('小明')
    time.sleep(1)
    teacher.call('小亮')
    time.sleep(1)
    s3 = Student(name="小话", queue=queue)
    s3.start()
    teacher.call('小话')
    time.sleep(1)
    teacher.call('小亮')
    time.sleep(1)
    teacher.call('小明')

if __name__ == "__main__":
    main()

添加全局变量all_student = list(),存放student线程,如果点名不在student线程中就不put数据到队列中。
总结:队列先进先出,先取数据。如上问题,点名小花,会导致代码死循环,可以设置标志,当重新遇到自己线程设置的标志位就暂停put数据到队列中。下一章基于这个原理实现socket客户端之间相互发送消息