多个同时网络连接 - Telnet 服务器,Python
Posted
技术标签:
【中文标题】多个同时网络连接 - Telnet 服务器,Python【英文标题】:Multiple simultaneous network connections - Telnet server, Python 【发布时间】:2010-10-21 00:57:00 【问题描述】:我目前正在用 Python 编写一个 telnet 服务器。它是一个内容服务器。人们将通过 telnet 连接到服务器,并显示纯文本内容。
我的问题是服务器显然需要支持多个同时连接。我现在的当前实现只支持一个。
这是我开始使用的基本概念验证服务器(虽然程序随着时间的推移发生了很大变化,但基本的 telnet 框架没有):
import socket, os
class Server:
def __init__(self):
self.host, self.port = 'localhost', 50000
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.bind((self.host, self.port))
def send(self, msg):
if type(msg) == str: self.conn.send(msg + end)
elif type(msg) == list or tuple: self.conn.send('\n'.join(msg) + end)
def recv(self):
self.conn.recv(4096).strip()
def exit(self):
self.send('Disconnecting you...'); self.conn.close(); self.run()
# closing a connection, opening a new one
# main runtime
def run(self):
self.socket.listen(1)
self.conn, self.addr = self.socket.accept()
# there would be more activity here
# i.e.: sending things to the connection we just made
S = Server()
S.run()
感谢您的帮助。
【问题讨论】:
【参考方案1】:在twisted中实现:
from twisted.internet.protocol import Factory, Protocol
from twisted.internet import reactor
class SendContent(Protocol):
def connectionMade(self):
self.transport.write(self.factory.text)
self.transport.loseConnection()
class SendContentFactory(Factory):
protocol = SendContent
def __init__(self, text=None):
if text is None:
text = """Hello, how are you my friend? Feeling fine? Good!"""
self.text = text
reactor.listenTCP(50000, SendContentFactory())
reactor.run()
测试:
$ telnet localhost 50000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello, how are you my friend? Feeling fine? Good!
Connection closed by foreign host.
说真的,当涉及到异步网络时,twisted 是要走的路。它以单线程单进程的方式处理多个连接。
【讨论】:
这是完美的。你能举一个从客户端发送和接收数据的例子吗?我正在阅读 Twisted,但它的教程非常冗长。 @SpleenTea:只需在协议上添加一个 dataReceived 方法,数据就会发送到它。如果您的协议是基于行的,您可能希望子类化 twisted.protocols.basic.LineReceiver 而不是 Protocol,因此您只需定义 lineReceived,它将为您从客户端获得的每一行调用。发送只需使用 self.transport.write 就像我在上面的示例中所做的那样。 twistedmatrix.com/projects/core/documentation/howto 很有用,特别是教程。【参考方案2】:您需要某种形式的异步套接字 IO。看看this explanation,它讨论了低级套接字术语的概念,以及用 Python 实现的相关示例。这应该会为您指明正确的方向。
【讨论】:
【参考方案3】:回复晚了,但唯一的答案是 Twisted 或线程(哎哟),我想为 MiniBoa 添加一个答案。
http://code.google.com/p/miniboa/
Twisted 很棒,但它是一个相当大的野兽,可能不是单线程异步 Telnet 编程的最佳介绍。 MiniBoa 是一个轻量级的异步单线程 Python Telnet 实现,最初是为泥浆设计的,非常适合 OP 的问题。
【讨论】:
【参考方案4】:使用 SocketServer 和 SocketServer.ThreadingMixIn 实现一个真正轻松的解决方案
看看这个回显服务器示例,它看起来与您正在做的事情非常相似:http://www.oreillynet.com/onlamp/blog/2007/12/pymotw_socketserver.html
【讨论】:
-1:SocketServer 对每个连接使用一个线程,这是一种非常糟糕的方法。 是的,你是对的,我曾经做过一个 xmlrpc 服务器,它通过调用 xmlrpc 服务的 vba 函数与 excel 进行通信。它运行良好,直到有人填写了大约 1000 行的公式,此时定义的函数调用了我的 xmlrpc 服务 1000 次,创建了 1000 个线程。不好玩。扭曲的方法当然是要走的路。【参考方案5】:如果您愿意接受一些概念上的挑战,我会考虑使用twisted。
作为twisted 的一部分,您的案例应该很容易实现。 http://twistedmatrix.com/projects/core/documentation/howto/servers.html
【讨论】:
+1:扭曲是要走的路。实现一个简单的 telnet 服务器应该很容易。【参考方案6】:如果你想用纯 python (sans-twisted) 来做,你需要做一些线程。如果您以前没有看过,请查看: http://heather.cs.ucdavis.edu/~matloff/Python/PyThreads.pdf
第 5/6 页附近是一个非常相关的示例;)
【讨论】:
-1:文章是关于线程的一般文章。示例与套接字无关。用线程实现一个好的套接字服务器很棘手,有很多细节,很难调试,而且你没有任何好处。没有理由不去异步。 p.5底部(srvr.py)是一个使用socket接口绑定到端口并监听连接的服务器。你说得对。它与当前对套接字的讨论无关。我的错。【参考方案7】:首先,在TCP/IP programming 上购买 Comer 的书籍。
在这些书中,Comer 将为服务器提供几种替代算法。有两种标准方法。
每个请求线程。
按请求处理。
您必须选择这两者之一并实施。
在 thread-per 中,每个 telnet 会话都是整个应用程序中的一个单独线程。
在 process-per 中,您将每个 telnet 会话分叉到一个单独的子进程中。
您会发现在 Python 中处理每个请求的过程要容易得多,而且通常可以更有效地利用您的系统。
Thread-per-request 适用于快速来去匆匆的事情(例如 HTTP 请求)。 Telnet 有长时间运行的会话,其中子进程的启动成本不会影响性能。
【讨论】:
-1:Thread-per-request 和 process-per-request 都无法扩展到一定数量的同时请求。 @nosklo: "some number" 没有什么可以扩展到某些数字,因为它们太大了。每个请求的线程通常被认为是非常可扩展的。你有什么替代品的具体细节吗? 不要将你的并发模型绑定到每个请求。相反,运行多个独立于请求数量的进程/线程。在同一个进程/线程中处理许多请求,最好使用异步 IO。这样可以更好地扩展。【参考方案8】:试试 MiniBoa 服务器?它恰好有 0 个依赖项,不需要扭曲或其他东西。 MiniBoa 是一个非阻塞异步远程登录服务器,单线程,正是您所需要的。
http://code.google.com/p/miniboa/
【讨论】:
【参考方案9】:使用线程,然后将处理程序添加到函数中。每次我发出请求时线程都会调用:
看看这个
import socket # Import socket module
import pygame
import thread
import threading,sys
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
port = 12345 # Reserve a port for your service.
s.bind((host, port))
print ((host, port))
name = ""
users = []
def connection_handler (c, addr):
print "conn handle"
a = c.recv (1024)
if a == "c":
b = c.recv (1024)
if a == "o":
c.send (str(users))
a = c.recv (1024)
if a == "c":
b = c.recv (1024)
print a,b
s.listen(6) # Now wait for client connection.
while True:
c, addr = s.accept()
print 'Connect atempt from:', addr[0]
username = c.recv(1024)
print "2"
if username == "END_SERVER_RUBBISH101":
if addr[0] == "192.168.1.68":
break
users.append(username)
thread.start_new_thread (connection_handler, (c, addr)) #New thread for connection
print
s.close()
【讨论】:
以上是关于多个同时网络连接 - Telnet 服务器,Python的主要内容,如果未能解决你的问题,请参考以下文章