0

我正在用 Python 编写一个多线程套接字应用程序。

这是我所拥有的一些基本骨架代码:

import socket, threading, time

class listener:

    def __init__(self):
        # Create a local listener socket
        self.socket = socket.socket(AF_INET, SOCK_STREAM)
        # Set options
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    def start(self):
        # Start listening for incoming connections in a loop. As connections
        # come in, start new threads and accept/work with them.
        self.socket.bind(('',1001)) # Bind to all addresses
        while (True):
            self.socket.listen(1) # blocks until a new connection is available
            newSocket, addr = self.socket.accept() # Accept connection
            thisConnThread = threading.Thread(target=server().runServer, args=( newSocket, addr ) )
            thisConnThread.start() # call the connection handler on a new thread
            # now return and listen for more connections.

class server:
    def RunServer(self, socket, addr):
        socket.write("Hello world!\n")
        # Create a thread to listen for input from the client
        thisListenThread = threading.Thread(target=self.RunServer_Listener, args=(socket.) )
        thisListenThread.start()
        # To demonstrate async - print a value every so many seconds - this 
        # needs to happen separately from the listener.
        for i in range(0,100):
            socket.write("Checkpoint!\n")
            time.sleep(60)
        socket.write("Your time is UP! Bye!\n")
        socket.shutdown(socket.SHUTDOWN_RDWR) # close the connection

    def RunServer_Listener(self, socket):
        while (True):
            inData = socket.read(4096) # blocks until data arrives
            if not inData:
                break # connection must be closed
            socket.write("You wrote: %s\n" % inData)

在这种情况下,我期望发生的是,每次连接进入时,server都会创建一个新的实例,并产生一个新的线程来运行它。

换句话说,thisConnThread = threading.Thread(target=server().runServer, args=( newSocket, addr ) )对我来说应该是创建一个新实例,server然后执行其中包含的函数。

我设置了一个单独的监听线程,因为在实际的服务器上,服务器可能需要随时向客户端发送数据,但它也需要随时响应客户端。由于 read() 阻塞直到数据可用,所以创建一个侦听线程来等待来自客户端的输入然后处理它对我来说是有意义的,但是主连接线程仍然可以做它需要做的事情并写入客户端独立于听者。

如果我与该服务器有一个连接,则可以完全按预期工作。

但是,如果我将第二个客户端连接到服务器,就会开始发生奇怪的事情。最重要和最令人担忧的是,如果我在第二个实例的客户端中输入,有时回复会转到第二个实例,有时会转到第一个实例,反之亦然。就好像 write() 操作正在做某种循环的事情——它交替地进入每个实例。

对于这个练习,真的不需要像一个活动连接列表一样保留。这可能适用于以后或更高级的项目,但就目前而言,客户端只是在服务器上度过他们的时间然后离开,服务器没有任何理由与其他连接进行交互。

我确定我在这里遗漏了一些东西,也许我的线程实现是错误的,或者我对套接字的使用完全错误。无论哪种方式,是否有人对如何使与服务器的连接完全相互独立有一些建议?

4

1 回答 1

1

在进行了一些或多或少明显的修复之后,您的代码在 Python 2.7 中似乎对我来说可以正常工作。这是补丁(注意,我也更改了端口号,并加快了超时等)。

(没有添加适当的joinsetDaemon调用,似乎不值得这样做。)

diff --git a/fdmillion.py b/fdmillion.py
index 8109c83..1362d3d 100644
--- a/fdmillion.py
+++ b/fdmillion.py
@@ -1,40 +1,44 @@
 import socket, threading, time
+from socket import AF_INET, SOCK_STREAM

 class listener:

     def __init__(self):
         # Create a local listener socket
-        self.socket = socket.socket(AF_INET, SOCK_STREAM)
+        self.sock = socket.socket(AF_INET, SOCK_STREAM)
         # Set options
-        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     def start(self):
         # Start listening for incoming connections in a loop. As connections
         # come in, start new threads and accept/work with them.
-        self.socket.bind(('',1001)) # Bind to all addresses
+        self.sock.bind(('',8001)) # Bind to all addresses
         while (True):
-            self.socket.listen(1) # blocks until a new connection is available
-            newSocket, addr = self.socket.accept() # Accept connection
-            thisConnThread = threading.Thread(target=server().runServer, args=(  newSocket, addr ) )
+            self.sock.listen(1) # blocks until a new connection is available
+            newSocket, addr = self.sock.accept() # Accept connection
+            thisConnThread = threading.Thread(target=server().RunServer, args=(  newSocket, addr ) )
             thisConnThread.start() # call the connection handler on a new thread
             # now return and listen for more connections.

 class server:
-    def RunServer(self, socket, addr):
-        socket.write("Hello world!\n")
+    def RunServer(self, sock, addr):
+        sock.sendall("Hello world!\n")
         # Create a thread to listen for input from the client
-        thisListenThread = threading.Thread(target=self.RunServer_Listener, args=(socket.) )
+        thisListenThread = threading.Thread(target=self.RunServer_Listener, args=(sock,) )
         thisListenThread.start()
         # To demonstrate async - print a value every so many seconds - this 
         # needs to happen separately from the listener.
-        for i in range(0,100):
-            socket.write("Checkpoint!\n")
-            time.sleep(60)
-        socket.write("Your time is UP! Bye!\n")
-        socket.shutdown(socket.SHUTDOWN_RDWR) # close the connection
+        for i in range(5,0,-1):
+            sock.sendall("Checkpoint! %d...\n" % i)
+            time.sleep(5)
+        sock.sendall("Your time is UP! Bye!\n")
+        sock.shutdown(socket.SHUT_RDWR) # close the connection

-    def RunServer_Listener(self, socket):
+    def RunServer_Listener(self, sock):
         while (True):
-            inData = socket.read(4096) # blocks until data arrives
+            inData = sock.recv(4096) # blocks until data arrives
             if not inData:
                 break # connection must be closed
-            socket.write("You wrote: %s\n" % inData)
+            sock.sendall("You wrote: %s\n" % inData)
+
+if __name__ == '__main__':
+    listener().start()

[编辑以修复通过差异输出切断的长线less]

于 2013-06-24T01:31:48.640 回答