Многопоточный многопользовательский сервер в Python - PullRequest
0 голосов
/ 05 апреля 2011

Я пишу многопоточный, многопользовательский сервер на 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,))

Ответы [ 3 ]

2 голосов
/ 05 апреля 2011

Гораздо проще и лучше реализовать такие вещи, используя Twisted , который позволяет одновременно обрабатывать несколько клиентов в одном потоке, а также предоставляет более удобный API.

Воткак вы пишете сервер чата с использованием Twisted (полный пример в 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')

Для каждого пользователя создается объект MyChat, и цикл обработки событий вызывает егометоды для запуска / остановки событий и когда строка получена от клиента.В этом случае он просто отправляет каждую полученную строку всем клиентам в системе.Поскольку он работает в одном потоке, блокировки не нужны.

0 голосов
/ 24 июня 2011

Я думаю, вам нужно вызывать s.listen перед каждым подключением. То есть положить его в бесконечный цикл. while True: acceptor.listen(1) #...

0 голосов
/ 05 апреля 2011

Это не так, как вы используете global.Когда вы определяете метод, в области действия метода вы используете глобальную команду, чтобы сделать ссылки на переменную переменной более высокого уровня.

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

print message
globalTest()
print message

Вы создаете новый файловый объект для соединения каждый раз, когда выперебрать цикл.Вы хотите сделать это до начала цикла, поэтому вы делаете это только один раз.

Вы читаете и пишете в один и тот же объект файла.Это означает, что это просто эхо-сервер.Вы никогда не даете thread1 ссылку на файл thread2.Попытка использовать одну глобальную переменную для файла сокета не будет работать, потому что вы никогда не узнаете, на какой сокет он указывает.(Проблема № 2)

Вы никогда не инициализируете сообщение, поэтому message += temp выдаст UnboudLocalError, сообщающее, что на него ссылаются до присвоения значения.(Вероятно, причина проблемы # 1) Кроме того, почему вы добавляете строку в первую очередь, это означает, что каждый раз, когда что-то отправляется, весь разговор отправляется.

Кроме того, не запрашивайте вручнуюи отпустите замок, используя с очистителем.

with lock:
  message += temp
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...