Python服务器客户端彩票问题

时间:2019-09-25 02:13:36

标签: python python-3.x sockets

我在执行python作业时遇到问题,想向社区寻求指导。我仅将 socket模块 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 -l 1

  • 指定要连接到服务器的IP地址(例如localhost或127.0.0.1)
  • 指定要连接的端口,例如4444

当客户端与服务器之间建立连接时,服务器会接收客户端输入并在其末端打印游戏类型(Lotto_Max),票证数量和每张票证的行数

服务器将输出结果,例如

server side lottery

但是,客户不会无限期收到它。通常,它会在大约25%的时间内得到解决,但我不确定为什么

2 个答案:

答案 0 :(得分:0)

服务器中的一个问题是

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()

这是成功连接数百次后的结果。注意成功连接和失败连接之间的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)来精确读取{{ 1}}个字节(来自套接字),或n个字节来读取.readline()终止的行。

以下是我的答案的链接,它证明了这一点:https://stackoverflow.com/a/55840026/235698

TCP的流传输性质的另一个示例是在客户端。有时,它会打印:

\n

服务器中的单独行:

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

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

有时会被客户端中的单个conn.sendall(liners.encode("utf-8")) conn.sendall(b'goodbye') 接收:

recv

同样,这是由于TCP的流式传输特性,并且没有消息边界。如果您发送的每行都以换行符结尾,则可以多次调用server_data = kulmiye.recv(1024).decode("utf-8") 直到检测到换行符,然后仅处理该行。

另一个说明此技术的答案在这里:https://stackoverflow.com/a/55186805/235698

答案 1 :(得分:0)

谢谢Mark Tolonen的指导。我仍然需要复习如何处理TCP数据流。尽管如此,我还是可以通过大量的操作获得更理想的结果 conn.sendall在我的嵌套for循环中。快乐的露营者!