Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.3k views
in Technique[技术] by (71.8m points)

关于socketserver线程之间的通信

这程序主要是用socketserver监听2个端口,一个9999,一个10000
设计是不管哪个端口的连接,都放到类属性conn_pool中保存起来
程序会将9999端口的连接,收到的数据,发送给10000端口的连接。将10000端口的连接,收到的数据,发送给9999端口的连接。

现在的问题是,类属性conn_pool只能保存同端口的连接进去。如当10000、9999端口各有1个连接,但在def setup(self):回显出来。print(MySelfServer.conn_pool.qsize())都是1。(正确应该是2的)问题出在哪呢?

创建服务器用到的模块
import socketserver
from multiprocessing import Process
from queue import Queue

第一步创建一个自己的server类,继承BaseRequestHandler类
class MySelfServer(socketserver.BaseRequestHandler):

conn_pool = None

def __init__(self, conn_pool):
    MySelfServer.conn_pool = conn_pool

def __call__(self, request, client_address, server):
    h = MySelfServer(MySelfServer.conn_pool)
    socketserver.BaseRequestHandler.__init__(h, request, client_address, server)

def setup(self):
    self.request.sendall("Successfully connected to the server!".encode(encoding='utf-8'))
    # self.request 相当于一个conn
    # 加入连接池
    print(id(self.request))
    MySelfServer.conn_pool.put(self.request)
    print(MySelfServer.conn_pool.qsize())


def finish(self):
    print("This client is cleared")


def remove(self):
    print("A client is offline")
    MySelfServer.conn_pool.get(self.request)

# 重写BaseRequestHandler类中的handle方法,直接写在自己创建的类中就可以了
def handle(self):  # 里面的内容为服务器端跟客户端的所有交互
    try:
        while True:
            # 接收数据
            self.data = str(self.request.recv(1024).strip(), encoding='utf-8')

            if len(self.data) == 0:
                continue
            # 打印客户端ip地址和发送来的数据,这里可能会问为什么会有self.client_address这个参数,这个在父类构造函数中
            print(f'{self.client_address[0]}发送信息过来了,内容为:{self.data}')

            for i in MySelfServer.conn_pool:
                # 将内容发送到连接本端口的所有连接,但当前连接除外,因为是它发的。有点像聊天室
                if i != self.request and self.request.getsockname()[1] == i.getsockname()[1]:
                    i.sendall(bytes(self.data, encoding='utf-8'))
    except Exception as e:
        print(e)
        print(self.client_address, "连接断开")
    finally:
        self.request.close()

if name == "__main__":

HOST = "0.0.0.0"
PORT_1 = 9999
PORT_2 = 10000
server1 = None
server2 = None
# 连接池

# 队长是线程安全的,自带锁
g_conn_pool = Queue()

# 允许服务器重新绑定一个之前使用过的端口号。
socketserver.ThreadingTCPServer.allow_reuse_address = True
# 第二步实例化四个类其中之一并传入服务器地址和上面自己创建的服务器类,这里自己实例化的TCPServer
server1 = socketserver.ThreadingTCPServer((HOST, PORT_1), MySelfServer(g_conn_pool))

server2 = socketserver.ThreadingTCPServer((HOST, PORT_2), MySelfServer(g_conn_pool))

# 允许重用地址
server1.allow_reuse_address = True
server2.allow_reuse_address = True

p = Process(target=server2.serve_forever, args=())
p.start()

# server1需放在p.start后启动不然会阻塞进程,server2无法启动
server1.serve_forever()

# 主线程等待p线程的结束才退出程序
p.join()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
等待大神解答

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...