python 多线程多客户端服务器

发布于 2024-10-30 19:33:10 字数 1763 浏览 5 评论 0原文

我正在用 python 编写一个多线程、多客户端服务器。多个用户可以通过 telnet 连接到它,基本上将它用作聊天服务器。我可以通过 telnet 连接两个客户端,但遇到以下两个问题:

  1. 第一个发送消息的客户端立即断开连接。
  2. 另一个客户端不会接收第一个客户端发送的消息。

服务器代码:

import os
import sys
import socket
import thread

port = 1941
global message
global lock
global file

def handler(connection):
    while 1:
            file = connection.makefile()
            file.flush()
            temp = file.readline()
            if temp == 'quit':
                break
            lock.acquire()
            message += temp
            lock.release()
            file.write(message)
    file.close()

acceptor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
acceptor.bind(('', port))
acceptor.listen(10)
lock = thread.allocate_lock()

while 1:
    connection, addr = acceptor.accept()
    thread.start_new_thread(handler, (connection,))

好的,我听了 unholysampler,现在我有了这个。我现在可以连接两个客户端并输入消息,但它们没有被发送/接收(我不知道是哪一个)。

import os
import sys
import socket
import thread

port = 1953

def handler(connection):
    global message
    global filelist
    filelist = []
    file = connection.makefile()
    file.flush()
    filelist.append(file)
    message = ''
    while 1:
        i = 0
        while i < (len(filelist)):
            filelist[i].flush()
            temp = filelist[i].readline()

            if temp == 'quit':
                break

            with lock:
                message += temp

            i = i + 1
    file.close()

global lock
acceptor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
acceptor.bind(('', port))
acceptor.listen(10)
lock = thread.allocate_lock()

while 1:
    connection, addr = acceptor.accept()
    thread.start_new_thread(handler, (connection,))

I'm writing a multi-threaded, multi-client server in python. Multiple users can connect to it with telnet and basically use it as a chat server. I'm able to connect with two clients through telnet, but I run into the two following problems:

  1. The first client to send a message is immediately disconnected.
  2. The other client does not the receive the message sent by the first client.

Server code:

import os
import sys
import socket
import thread

port = 1941
global message
global lock
global file

def handler(connection):
    while 1:
            file = connection.makefile()
            file.flush()
            temp = file.readline()
            if temp == 'quit':
                break
            lock.acquire()
            message += temp
            lock.release()
            file.write(message)
    file.close()

acceptor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
acceptor.bind(('', port))
acceptor.listen(10)
lock = thread.allocate_lock()

while 1:
    connection, addr = acceptor.accept()
    thread.start_new_thread(handler, (connection,))

Ok I listened to unholysampler and now I have this. I'm able to to connect with both clients now and type messages, but they aren't being sent/received (I can't tell which one).

import os
import sys
import socket
import thread

port = 1953

def handler(connection):
    global message
    global filelist
    filelist = []
    file = connection.makefile()
    file.flush()
    filelist.append(file)
    message = ''
    while 1:
        i = 0
        while i < (len(filelist)):
            filelist[i].flush()
            temp = filelist[i].readline()

            if temp == 'quit':
                break

            with lock:
                message += temp

            i = i + 1
    file.close()

global lock
acceptor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
acceptor.bind(('', port))
acceptor.listen(10)
lock = thread.allocate_lock()

while 1:
    connection, addr = acceptor.accept()
    thread.start_new_thread(handler, (connection,))

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

故笙诉离歌 2024-11-06 19:33:10

使用 Twisted 实现此类事情要简单得多,效果更好,它允许您在单个线程中同时处理多个客户端,以及提供更好的 API。

以下是如何使用 Twisted 编写聊天服务器(完整示例位于 聊天服务器中。 py):

class MyChat(basic.LineReceiver):
    def connectionMade(self):
        print "Got new client!"
        self.factory.clients.append(self)

    def connectionLost(self, reason):
        print "Lost a client!"
        self.factory.clients.remove(self)

    def lineReceived(self, line):
        print "received", repr(line)
        for c in self.factory.clients:
            c.message(line)

    def message(self, message):
        self.transport.write(message + '\n')

对于每个用户,都会创建一个 MyChat 对象,事件循环会在开始/停止事件以及从客户端收到一行时调用其方法。在这种情况下,它只是将收到的每一行发送给系统中的所有客户端。由于它在单线程中运行,因此不需要锁。

It's much simpler and better to implement this sort of thing using Twisted, which lets you handle multiple clients concurrently in a single thread, as well as providing a nicer API.

Here's how you write a chat server using Twisted (full example in chatserver.py):

class MyChat(basic.LineReceiver):
    def connectionMade(self):
        print "Got new client!"
        self.factory.clients.append(self)

    def connectionLost(self, reason):
        print "Lost a client!"
        self.factory.clients.remove(self)

    def lineReceived(self, line):
        print "received", repr(line)
        for c in self.factory.clients:
            c.message(line)

    def message(self, message):
        self.transport.write(message + '\n')

For each user, a MyChat object gets created, and the event loop calls its methods for start/stop events and when a line is received from the client. In this case, it just send every line it receives to all the clients in the system. Since it runs in a single thread, no locks are needed.

依 靠 2024-11-06 19:33:10

这不是您使用global的方式。当您在方法作用域内定义方法时,可以使用全局命令来引用更高作用域的变量。

message = 1
def globalTest():
  global message
  message += 1
  print message

print message
globalTest()
print message

每次迭代循环时,您都会为连接创建一个新的文件对象。您想在循环开始之前进行此操作,因此只需执行一次。

您正在读取和写入同一个文件对象。这意味着它只是一个回显服务器。您永远不会向 thread1 提供对 thread2 文件的引用。尝试对套接字文件使用一个全局变量是行不通的,因为您永远不知道它实际上指向哪个套接字。 (问题#2)

您从不初始化消息,因此 message += temp 将抛出一个 UnboudLocalError ,表示在赋值之前它已被引用。 (可能是问题 #1 的原因)另外,为什么要首先附加字符串,这意味着每次发送内容时,整个对话都会发送出去。

另外,不要手动获取和释放锁,使用 with 更干净。

with lock:
  message += temp

That's not how you use global. When you define a method, inside the method scope, you use the global command to make references to the variable the the higher scoped variable.

message = 1
def globalTest():
  global message
  message += 1
  print message

print message
globalTest()
print message

You are making a new file object for the connection every time you iterate over the loop. You want to make that before the loop starts so you are only doing it once.

You are reading from and writing to the same file object. This means it is just an echo server. You are never giving thread1 a reference to thread2's file. Trying to use one global variable for the socket file will not work because you will never know which socket it is actually pointing to. (Issue #2)

You never initialize message, so message += temp will throw an UnboudLocalError saying that it is being referenced before assigned a value. (Likely the cause of issue #1) Also, why are you appending the string in the first place, that means every time something is sent, the entire conversation is sent out.

Also, don't manually acquire and release the lock, using with is cleaner.

with lock:
  message += temp
没有心的人 2024-11-06 19:33:10

我认为你需要在每次连接之前调用 s.listen 。也就是将其放入无限循环中。
当为真时:
接受器.listen(1)
#...

I think you need to call s.listen before every single connection. That is put it inside the infinite loop.
while True:
acceptor.listen(1)
#...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文