Невозможно установить соединение клиент-сервер через сокеты в Python - PullRequest
3 голосов
/ 18 ноября 2011

Последние две недели я бился головой о проблеме с розеткой, но безрезультатно.У меня есть установка из 12 «клиентских» машин и одна серверная машина.Перед сервером стоит большая задача, она разбивается на 12 небольших задач и затем распределяется по 12 клиентам.Клиенты расходятся, и, как только они заканчивают свою задачу, они должны сообщить серверу, что они закончили через сокетную связь.По какой-то причине это работало только спотти или не работало вообще (и сервер, и клиенты просто находились в цикле while).

Вот код на сервере:

socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.bind(('localhost', RandomPort))
socket.listen(0)
socket.settimeout(0.9)

[Give all the clients their tasks, then do the following:]

while 1:
    data = 'None'
    IP = [0,0]   
    try:
        Client, IP = socket.accept()
        data = Client.recv(1024)
        if data == 'Done':
            Client.send('Thanks')
        for ClientIP in ClientIPList():
            if ClientIP == IP[0] and data == 'Done':
                FinishedCount += 1 
            if FinishedCount == 12:
                break
    except:
        pass

Вот код на всех клиентах:

[Receive task from server and execute. Once finished, do the following:]

while 1:
    try:
        f = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        f.connect((IPofServer, RandomPort)) 
        f.settimeout(0.5)
        f.send('Done')
        data = f.recv(1024)
        if data == 'Thanks':
            f.shutdown(socket.SHUT_RDWR)
            f.close()
            break
    except:
        f.close()
        time.sleep(2+random.random()*5)

Я использовал Wireshark и обнаружил, что пакетылетают вокруг.Тем не менее, «FinishedCount», кажется, никогда не увеличивается ... Есть ли что-то явно неправильное, что я упустил при настройке этого?Это мое первое знакомство с сокетами ....

Спасибо всем за вашу помощь заранее!

РЕДАКТИРОВАТЬ: я внес следующие изменения в код:

На сервере: socket.listen теперь является socket.listen (5)

Ответы [ 5 ]

3 голосов
/ 21 ноября 2011

Хорошо, это заняло у меня некоторое время, но я думаю, я понял, что было причиной этого:

  1. ответ glglgl верен - использование localhost заставляет машину слушайте только себя, а не другие машины в сети. это был главным виновником.
  2. Увеличение допустимого числа в очереди с 0 до 5 уменьшило вероятность получения ошибки «отказано в соединении» на клиенте сторона.
  3. Я допустил ошибку, предположив, что сокетные соединения в бесконечном в то время как цикл может быть отключен бесконечно быстро - однако, имея бесконечный цикл while с обеих сторон иногда вызывал у клиента иногда считаются дважды, потому что циклы while не были синхронизированы. Это, конечно, вызвало «независимость от клиента» Закончено увеличить счет в два раза, что привело к клиенты были сделаны, когда они не были. Используя код Чоуна (спасибо chown!), с этим можно справиться так:

    def main():
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind((HOST, PORT))
        sock.listen(0)
    
        FINISHEDCLIENTS = []
    
        while 1:
            data = 'None'
            IP = [0, 0]
            try:
                client, ip = sock.accept()
                data = client.recv(1024)
                print "%s: Server recieved: '%s'" % (time.ctime(), data)
    
                if data == 'Done':
                    print "%s: Server sending: 'Thanks'" % time.ctime()
                    client.send('Thanks')
    
                    if ip[0] in CLIENT_IPS and ip[0] not in FINISHEDCLIENTS: 
                        FINISHEDCLIENTS.append(ip[0])
    
                        if len(FINISHEDCLIENTS) == 12:
                            #raise MyException
                            break
    
            except Exception, e:
                print "%s: Server Exception - %s" % (time.ctime(), e)
    

    На стороне клиента я изменил код на этот (где, конечно, RandomPort такой же, как и в приведенном выше сценарии сервера):

    SentFlag = 0
    data = 'no'
    while SentFlag == 0:
        try:
            f = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            f.connect((IPofServer, RandomPort))
            f.settimeout(20)
            f.send('Done')
            data = f.recv(1024)
            if data == 'Thanks':
                f.shutdown(socket.SHUT_RDWR)
                f.close()
                SentFlag = 1
        except:
            f.close()
            time.sleep(2*random.random())
    

PS: Мое понимание .shutdown () против .close () заключается в том, что закрывается соединение, но не обязательно, если он занят другим обменом данными. .shutdown () выключает сокет независимо от того, что еще он делает. У меня нет никаких доказательств этого.

Я думаю, что так и должно быть - еще раз спасибо всем за помощь в исправлении этого кода!

2 голосов
/ 18 ноября 2011

Я считаю, что проблема здесь заключается в использовании RandomPort. Каждый клиент и сервер должны отправлять / получать по одному и тому же порту, чтобы это работало. Кроме того, цикл for ClientIP in ClientIPList(): if ClientIP == IP[0] and data == 'Done': немного избыточен и не нужен. Его можно заменить на if ip[0] in clientIpList: и поместить внутри if data == 'Done': над ним.

Несколько других мыслей; никогда не называйте переменную таким же именем, как у того, что вы импортировали (например, socket = socket.socket(..)), потому что тогда вы больше не сможете использовать импортированную библиотеку. И если клиент / сервер не работают в одной и той же системе или в одной и той же подсети, settimeout(0.5) является коротким путем.

Я объединил ваш код с некоторым примером кода из python socket документации и придумал что-то, что работает, чтобы вы могли легко адаптироваться к вашим потребностям. Вот сценарии; вывод от запуска сервера и 12 клиентов вставлен ниже.

server.py:

#!/usr/bin/python
# server.py

import sys
import socket
import time

HOST = ''
PORT = 50008

CLIENT_IPS = ["10.10.1.11"]

## No longer necessary if the nested loop isn't needed
#class MyException(Exception):
#    pass

def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind((HOST, PORT))
    sock.listen(0)

    finishedCount = 0

    while 1:
        data = 'None'
        IP = [0, 0]
        try:
            client, ip = sock.accept()
            data = client.recv(1024)
            print "%s: Server recieved: '%s'" % (time.ctime(), data)

            if data == 'Done':
                print "%s: Server sending: 'Thanks'" % time.ctime()
                client.send('Thanks')

                if ip[0] in CLIENT_IPS:
                    finishedCount += 1
                    print "%s: Finished Count: '%d'" % (time.ctime(), finishedCount)

                    if finishedCount == 12:
                        #raise MyException
                        break

        except Exception, e:
            print "%s: Server Exception - %s" % (time.ctime(), e)

        #except MyException:
        #    print "%s: All clients accounted for.  Server ending, goodbye!" % time.ctime()
        #    break

    # close down the socket, ignore closing exceptions
    try:
        sock.close()
    except:
        pass
    print "%s: All clients accounted for.  Server ending, goodbye!" % time.ctime()

if __name__ == '__main__':
    sys.exit(main())

client.py:

#!/usr/bin/python
# client.py

import sys
import time
import socket
import random

HOST = '10.10.1.11'
PORT = 50008

def main(n):
    while 1:
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((HOST, PORT))

            s.send('Done')
            print "%s: Client %d: Sending - 'Done'.." % (time.ctime(), n)

            data = s.recv(1024)
            print "%s: Client %d: Recieved - '%s'" % (time.ctime(), n, data)

            if data == 'Thanks':
                break

        except Exception, e:
            print "%s: Client %d: Exception - '%s'" % (time.ctime(), n, e)
            time.sleep(2 + random.random() * 5)
        finally:
            try:
                s.shutdown(socket.SHUT_RDWR)
            except:
                pass
            finally:
                try:
                    s.close()
                except:
                    pass

    print "%s: Client %d: Finished, goodbye!" % (time.ctime(), n)


if __name__ == '__main__':
    if len(sys.argv) > 1 and sys.argv[1].isdigit():
        sys.exit(main(int(sys.argv[1])))

Вывод из запущенных 12 клиентов:

[ 10:52 jon@hozbox.com ~/SO/python ]$ for x in {1..12}; do ./client.py $x && sleep 2; done
Fri Nov 18 10:52:44 2011: Client 1: Sending - 'Done'..
Fri Nov 18 10:52:44 2011: Client 1: Recieved - 'Thanks'
Fri Nov 18 10:52:44 2011: Client 1: Finished, goodbye!
Fri Nov 18 10:52:46 2011: Client 2: Sending - 'Done'..
Fri Nov 18 10:52:46 2011: Client 2: Recieved - 'Thanks'
Fri Nov 18 10:52:46 2011: Client 2: Finished, goodbye!
Fri Nov 18 10:52:48 2011: Client 3: Sending - 'Done'..
Fri Nov 18 10:52:48 2011: Client 3: Recieved - 'Thanks'
Fri Nov 18 10:52:48 2011: Client 3: Finished, goodbye!
Fri Nov 18 10:52:50 2011: Client 4: Sending - 'Done'..
Fri Nov 18 10:52:50 2011: Client 4: Recieved - 'Thanks'
Fri Nov 18 10:52:50 2011: Client 4: Finished, goodbye!
Fri Nov 18 10:52:52 2011: Client 5: Sending - 'Done'..
Fri Nov 18 10:52:52 2011: Client 5: Recieved - 'Thanks'
Fri Nov 18 10:52:52 2011: Client 5: Finished, goodbye!
Fri Nov 18 10:52:54 2011: Client 6: Sending - 'Done'..
Fri Nov 18 10:52:54 2011: Client 6: Recieved - 'Thanks'
Fri Nov 18 10:52:54 2011: Client 6: Finished, goodbye!
Fri Nov 18 10:52:56 2011: Client 7: Sending - 'Done'..
Fri Nov 18 10:52:56 2011: Client 7: Recieved - 'Thanks'
Fri Nov 18 10:52:56 2011: Client 7: Finished, goodbye!
Fri Nov 18 10:52:58 2011: Client 8: Sending - 'Done'..
Fri Nov 18 10:52:58 2011: Client 8: Recieved - 'Thanks'
Fri Nov 18 10:52:58 2011: Client 8: Finished, goodbye!
Fri Nov 18 10:53:01 2011: Client 9: Sending - 'Done'..
Fri Nov 18 10:53:01 2011: Client 9: Recieved - 'Thanks'
Fri Nov 18 10:53:01 2011: Client 9: Finished, goodbye!
Fri Nov 18 10:53:03 2011: Client 10: Sending - 'Done'..
Fri Nov 18 10:53:03 2011: Client 10: Recieved - 'Thanks'
Fri Nov 18 10:53:03 2011: Client 10: Finished, goodbye!
Fri Nov 18 10:53:05 2011: Client 11: Sending - 'Done'..
Fri Nov 18 10:53:05 2011: Client 11: Recieved - 'Thanks'
Fri Nov 18 10:53:05 2011: Client 11: Finished, goodbye!
Fri Nov 18 10:53:07 2011: Client 12: Sending - 'Done'..
Fri Nov 18 10:53:07 2011: Client 12: Recieved - 'Thanks'
Fri Nov 18 10:53:07 2011: Client 12: Finished, goodbye!
[ 10:53 jon@hozbox.com ~/SO/python ]$

Вывод с сервера, работающего одновременно:

[ 10:52 jon@hozbox.com ~/SO/python ]$ ./server.py
Fri Nov 18 10:52:44 2011: Server recieved: 'Done'
Fri Nov 18 10:52:44 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:44 2011: Finished Count: '1'
Fri Nov 18 10:52:46 2011: Server recieved: 'Done'
Fri Nov 18 10:52:46 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:46 2011: Finished Count: '2'
Fri Nov 18 10:52:48 2011: Server recieved: 'Done'
Fri Nov 18 10:52:48 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:48 2011: Finished Count: '3'
Fri Nov 18 10:52:50 2011: Server recieved: 'Done'
Fri Nov 18 10:52:50 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:50 2011: Finished Count: '4'
Fri Nov 18 10:52:52 2011: Server recieved: 'Done'
Fri Nov 18 10:52:52 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:52 2011: Finished Count: '5'
Fri Nov 18 10:52:54 2011: Server recieved: 'Done'
Fri Nov 18 10:52:54 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:54 2011: Finished Count: '6'
Fri Nov 18 10:52:56 2011: Server recieved: 'Done'
Fri Nov 18 10:52:56 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:56 2011: Finished Count: '7'
Fri Nov 18 10:52:58 2011: Server recieved: 'Done'
Fri Nov 18 10:52:58 2011: Server sending: 'Thanks'
Fri Nov 18 10:52:58 2011: Finished Count: '8'
Fri Nov 18 10:53:01 2011: Server recieved: 'Done'
Fri Nov 18 10:53:01 2011: Server sending: 'Thanks'
Fri Nov 18 10:53:01 2011: Finished Count: '9'
Fri Nov 18 10:53:03 2011: Server recieved: 'Done'
Fri Nov 18 10:53:03 2011: Server sending: 'Thanks'
Fri Nov 18 10:53:03 2011: Finished Count: '10'
Fri Nov 18 10:53:05 2011: Server recieved: 'Done'
Fri Nov 18 10:53:05 2011: Server sending: 'Thanks'
Fri Nov 18 10:53:05 2011: Finished Count: '11'
Fri Nov 18 10:53:07 2011: Server recieved: 'Done'
Fri Nov 18 10:53:07 2011: Server sending: 'Thanks'
Fri Nov 18 10:53:07 2011: Finished Count: '12'
Fri Nov 18 10:53:07 2011: All clients accounted for.  Server ending, goodbye!
[ 10:53 jon@hozbox.com ~/SO/python ]$
2 голосов
/ 18 ноября 2011

Ваш сервер имеет две ошибки:

Во-первых, это выйдет из внутреннего цикла for, а не цикла while:

if FinishedCount == 12:
    break

Ваш цикл while не имеет условия завершения.

Во-вторых, этот шаблон:

try:
    ...
except:
    pass

Если никогда не следует использовать. Вы проглатываете каждое исключение и игнорируете его. Это плохая практика и приведет к ошибкам. Должно быть:

try:
    ...
except OneExceptionIWantToIgnore:
    pass
except:
    raise

Исправьте эти два и вернитесь к нам с результатами.

0 голосов
/ 19 ноября 2011

Если вы сделаете

socket.bind(('localhost', RandomPort))

, ваш сервер будет принимать соединения только от себя, то есть от localhost.

Вместо этого выполните

socket.bind(('', RandomPort))

для прослушивания всехинтерфейсы.

0 голосов
/ 18 ноября 2011

Вызов listen (0) не устанавливает отставание, поэтому вы с большей вероятностью получите отказ в соединении.Сокет на стороне сервера также никогда не закрывается.Избавьтесь от try / excepts сейчас, чтобы вы могли увидеть реальные проблемы.В противном случае обработайте явные исключения socket.error.

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