Проблема с лотереей Python-сервер-клиент - PullRequest
0 голосов
/ 25 сентября 2019

У меня проблема с назначением Python, которое я выполнял, и я хотел бы попросить сообщество дать некоторые рекомендации.Я должен использовать модуль гнезда и argparse модули только для этого назначения.Я создал файл socketserver.py и файл socketclient.py.Связь между сервером и клиентом в порядке.Теперь цель задания состоит в том, чтобы клиент отправлял тип лотереи, количество билетов и количество строк на билеты, используя argparse .Например, синтаксис для socketclient.py будет выглядеть следующим образом: python3 -t Lotto_Max -n 2 -l 2. Выходные данные для игры с заявками, типа билетов и количества строк на билет отображаются правильно на сервере.Тем не менее, они иногда не отображаются правильно на клиенте, и я действительно застрял на данный момент.Вот мой следующий код ....

Код сервера

```socketserver.py code```

import socket
from random import sample

def main():
    host = input("Please specify an IP address for this server's socket\t")
    port = int(input('Please speciy a port number above 1024 for this socket.\t'))

    kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    try:
        kulmiye.bind((host, port))
    except socket.error as egeh:
        print('Socket bind failed. Error Code : ' + str(egeh[0]) + ' Message ' + egeh[1])

    print('Socket bind accomplished...\n')

    print("Listening for an incoming connection...")

    kulmiye.listen()
    conn, addr = kulmiye.accept()

    print('Connected with ' + addr[0] + ':' + str(addr[1]))

    while True:
        server_data = conn.recv(1024).decode("utf-8")
        game_data = server_data.split(",")
        if not server_data:
            break
        if game_data[0] == "Lotto_Max":
            nval = int(game_data[1])
            lval = int(game_data[2])
            for nval in range(nval):
                for i in range(lval):
                    numbers = sample(range(1, 50), 7)
                    numbers.sort()
                    sortedd = str(numbers)
                    print(sortedd)
                print("--------------------")
                conn.sendall(sortedd.encode("utf-8"))
                #conn.sendall(bytes(str(numbers),'utf-8'))
                liners = "-----------------------"
                conn.sendall(liners.encode("utf-8"))
            print("From Client: " + str(game_data))
            conn.sendall(b'goodbye')
    #        server_data = input('#\t')
            break
        else:
            conn.close()

if __name__ == '__main__':
    main()

Код клиента

```socketclient.py code```
import socket
import argparse

def client():
    host = input("Please specify the server's IP you want to connect to\t")
    port = int(input("Please specify the server's port you want to connect to\t"))

    kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    kulmiye.connect((host, port))

#    client_data = input("#\t")
#    while True:
#        client_data = input()
#        if client_data == 'quit':
#            kulmiye.close()
#            sys.exit()
#        if len(str.encode(client_data)) > 0:
#            kulmiye.sendall(str.encode(client_data))
#            server_response = str(kulmiye.recv(1024), "utf-8")

#            print(server_response, end = " ")

    kulmiye.sendall(bytes(tvar.encode("utf-8")))
    kulmiye.sendall(bytes(','.encode("utf-8")))
    kulmiye.sendall(bytes(str(nval).encode("utf-8")))
    kulmiye.sendall(bytes(','.encode("utf-8")))
    kulmiye.sendall(bytes(str(lval).encode("utf-8")))

    server_data = kulmiye.recv(1024).decode("utf-8")


    while server_data != 'goodbye':
        server_data = kulmiye.recv(1024).decode("utf-8")
        print('Server: \n' + server_data)
        #        client_data = input("#\t")
        if not server_data:
            break
    kulmiye.close()

# this code block serves to give the user the ability to play lotto max
# with the amount of tickets and lines per ticket they would like

# Using the argparse module to allow the user to input command-line interfaces
parser = argparse.ArgumentParser(description='Welcome to OLG Gaming.')
parser.add_argument(
    '-t',
    type=str,
    help="Pick the lottery you want to play",
    required=True)
parser.add_argument(
    '-n',
    type=int,
    help="Pick the amount of lottery tickets you want to play",
    required=True)
parser.add_argument(
    '-l',
    type=int,
    help="Pick the amount of lines you would like to play",
    required=True)
# parser.add_argument('-o', type = str, help = "This is optional", required = False)

# parse_args will convert the argument strings into objects and will get
# stored in the cmdargs variable
cmdargs = parser.parse_args()

tvar = cmdargs.t  # the t string argument that gets parsed into an object will get stored into a variable called tvar
# the n integer argument that gets parsed into an object will get stored

# into a variable called nval
nval = int(cmdargs.n)

# the l integer argument that gets parsed into an object will get stored
# into a variable called lval
lval = int(cmdargs.l)

if __name__ == "__main__":
    client()
```code```

Сервер

python3 socketserver.py

  • указать localhost как IP
  • указать порт, например 4444

Клиент

python3 socketclient.py -t Lotto_Max -n 1 -l1

  • укажите IP-адрес для подключения к серверу (например, localhost или 127.0.0.1)
  • укажите порт для подключения, например, 4444

Когда между клиентом и сервером устанавливается соединение, сервер получает данные клиента и распечатывает на своем конце тип игры (Lotto_Max), количество билетов и строк на билет

Сервер выдаст результатse.g.

server side lottery

Однако клиент не получит его на неопределенный срок.Обычно это происходит примерно в 25% случаев, и я не уверен, почему

Ответы [ 2 ]

0 голосов
/ 26 сентября 2019

Спасибо, Марк Толонен, за ваше руководство.Мне все еще нужно разобраться, как обрабатывать поток данных TCP.Тем не менее, я смог достичь более желательных результатов, используя многочисленные conn.sendall в рамках моего вложенного цикла for.Счастливого туриста!

0 голосов
/ 25 сентября 2019

На сервере есть одна проблема:

server_data = conn.recv(1024).decode("utf-8")

conn.recv(1024) может принимать любое количество байтов от 0 (закрытое соединение) до 1024. В строке выше предполагается, что сообщение целиком принимается каждый раз,но когда это терпит неудачу, это только получает часть сообщения.Ниже я изменил ваш код, чтобы сервер мог обрабатывать несколько клиентских подключений по одному, и клиент будет снова и снова подключаться / отключаться, чтобы ускорить сбой:

Сервер:

import socket
from random import sample

def main():
    host = ''
    port = 4444
    kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    kulmiye.bind((host, port))
    print('Socket bind accomplished...\n')
    print("Listening for an incoming connection...")
    kulmiye.listen()

    while True:
        conn, addr = kulmiye.accept()
        print('Connected with ' + addr[0] + ':' + str(addr[1]))
        with conn:
            server_data = conn.recv(1024).decode("utf-8")
            print(f'server_data={server_data}')
            game_data = server_data.split(",")
            print("From Client: " + str(game_data))
            if server_data:
                if game_data[0] == "Lotto_Max":
                    nval = int(game_data[1])
                    lval = int(game_data[2])
                    for nval in range(nval):
                        for i in range(lval):
                            numbers = sample(range(1, 50), 7)
                            numbers.sort()
                            sortedd = str(numbers)
                            print(sortedd)
                        print("--------------------")
                        conn.sendall(sortedd.encode("utf-8"))
                        liners = "-----------------------"
                        conn.sendall(liners.encode("utf-8"))
                    conn.sendall(b'goodbye')

if __name__ == '__main__':
    main()

Клиент:

import socket
import argparse

def client():
    host = 'localhost'
    port = 4444

    kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    kulmiye.connect((host, port))

    kulmiye.sendall(bytes(tvar.encode("utf-8")))
    kulmiye.sendall(bytes(','.encode("utf-8")))
    kulmiye.sendall(bytes(str(nval).encode("utf-8")))
    kulmiye.sendall(bytes(','.encode("utf-8")))
    kulmiye.sendall(bytes(str(lval).encode("utf-8")))

    server_data = kulmiye.recv(1024).decode("utf-8")

    while server_data != 'goodbye':
        server_data = kulmiye.recv(1024).decode("utf-8")
        print('Server: \n' + server_data)
        #        client_data = input("#\t")
        if not server_data:
            break
    kulmiye.close()

tvar = 'Lotto_Max'
nval = 1
lval = 1

if __name__ == "__main__":
    while True:
        client()

Вот результат после 100 с успешных соединений.Примечание server_data между успешным и неудачным соединением:

Connected with 127.0.0.1:12175
server_data=Lotto_Max,1,1
From Client: ['Lotto_Max', '1', '1']
[4, 7, 9, 12, 24, 31, 48]
--------------------
Connected with 127.0.0.1:12176
server_data=Lotto_Max,1,
From Client: ['Lotto_Max', '1', '']
Traceback (most recent call last):
  File "C:\server.py", line 38, in <module>
    main()
  File "C:\server.py", line 24, in main
    lval = int(game_data[2])
ValueError: invalid literal for int() with base 10: ''

conn.recv(1024) не получил полное сообщение (не получил окончательный 1).TCP - это протокол потоковой передачи байтов без понятия границ сообщения.Ваш код отвечает за вызов recv() и буферизацию данных до получения полного сообщения.Вы можете отправлять сообщения фиксированного размера и вызывать recv до тех пор, пока у вас не будет такого количества байтов, завершить сообщение байтом сторожа, таким как символ новой строки (\n), и читать до получения сторожа, или посылать размер сообщения, за которым следуетбайтами сообщения.

Я не буду решать это за вас, так как это назначение, но как подсказка socket.makefile может обернуть сокет в файлоподобный объект, где вы можете вызвать .read(n) длячитайте ровно n байтов из сокета или .readline(), чтобы прочитать \n строку с окончанием.

Вот ссылка на мой ответ, который демонстрирует это: https://stackoverflow.com/a/55840026/235698

Другой пример потоковой природы TCP - на стороне клиента.Иногда он печатает:

-----------------------
Server:
goodbye
Server:
-----------------------goodbye
Server:

Server:
-----------------------
Server:
goodbye

Отдельные строки на сервере:

conn.sendall(liners.encode("utf-8"))
conn.sendall(b'goodbye')

Иногда получаются единственными recv в клиенте:

server_data = kulmiye.recv(1024).decode("utf-8")

Опять же, это связано с потоковой природой TCP и отсутствием границ сообщений.Если вы отправляете каждую строку, оканчивающуюся новой строкой, вы можете вызывать recv() несколько раз, пока не будет обнаружена новая строка, а затем обработать только эту строку.

Другой ответ, иллюстрирующий эту технику, приведен здесь: https://stackoverflow.com/a/55186805/235698.

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