简体   繁体   中英

Python Error ValueError: invalid literal for int() with base 10 ' '

I am new to Python 3.3 and I am starting to write a little guessing game using sockets. However I keep getting the error ValueError: invalid literal for int() with base 10: ''
I can't see why I get this error in the line currentGuess = int(currentGuess) as I have a similar line earlier in my code. If anyone could help me I would be very grateful. Here is my server and Client code. I have looked at other solutions with similar problems but I can't get any to work for me.

Server

    #!/usr/bin/python
    import random
    import sys
    import math
    import  socket

    l = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    l.bind(("127.0.0.1", 4007))
    l.listen(5)
    print("Waiting...")
    while True:
          (s,  ca) = l.accept()
          print("Connection  from",  ca)

          #Name
          s.send("What is your name?". encode())
          names = s.recv(1024).decode()
          #Guesses

          s.send("How many guesses would you like?".encode())
          guesses = s.recv(1024).decode()
          guesses = int(guesses)
          #Random Number

          correctNumber = random.randrange(0,10)
          print(correctNumber)

          #Make Guesses
          count = 0
          while count < guesses:
                s.send("Take a Guess".encode())
                currentGuess = s.recv(1024).decode()
                currentGuess = int(currentGuess)
                if currentGuess == correctNumber:
                   s.send("You WIN".encode())
                if currentGuess != correctNumber:
                   s.send("Incorrect, Try Again ".encode())
                   count = count + 1

    s.close()

Client

    #!/usr/bin/python
    import random
    import sys
    import math
    import socket

    s = socket.socket(socket.AF_INET,   
    socket.SOCK_STREAM)
    s.connect(("127.0.0.1", 4007))
    print("Wlcome to the numer guessing game")

    #Name
    print(s.recv(1024).decode())
    name = sys.stdin.readline()
    s.send(name.encode())

    #guesses
    print(s.recv(1024).decode())
    guesses = sys.stdin.readline()
    s.send(guesses.encode())

    #Make Guesses
    print(s.recv(1024).decode())
    currentGuess = sys.stdin.readline()
    s.send(currentGuess.encode())
    print(s.recv(80).decode())
    s.close()

You get that error when you try to call int on an empty string:

>>> int("")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: ''

What this means is that when you do:

currentGuess = s.recv(1024).decode()
currentGuess = int(currentGuess)

currentGuess is being set to '' . That is, s.recv(1024) is returning an empty string. This only happens when the connection has closed, so it means the client has stopped sending data to the server.

Getting back an empty string from s.recv() means the other side called close or shutdown on the connection (or it was interrupted in some other way—the other side quit, or someone ripped out the Ethernet cord).

And looking at your server code, if you say you want 3 guesses, it will try to recv 3 times… but the client will only send once, after which it will close the connection. Which means the next recv on the server will return an empty string, which is exactly what you're seeing.

To fix this, you need to send as many guesses as the other side is expecting. Something like this:

#Make Guesses
for i in range(int(guesses)):
    print(s.recv(1024).decode())
    currentGuess = sys.stdin.readline()
    s.send(currentGuess.encode())
    print(s.recv(80).decode())
s.close()

Meanwhile, although it isn't causing this particular problem, your code can't work reliably. Sockets are byte streams, not message streams . There is no guarantee that each send will match up with a recv on the other side. The recv may get half of a send , or two send s bundled up together. On some platforms, when you're using localhost, and sending small messages, and not sending things too quickly, everything just happens to work out all the time. On other platforms, things work most of the time but occasionally don't. On others, they fail frequently.

On top of that, as the docs explain, send is never guaranteed to send its entire string; that's why it returns the number of bytes actually sent. You can solve this problem by just using sendall , but that won't help with the other problem.

You have to build a message stream on top of the TCP byte stream, by designing and implementing a protocol. That may sound scary, but a very simple protocol, "All messages end with a newline", can be implemented just by using the makefile method, like this:

s.connect(("127.0.0.1", 4007))
f = s.makefile('r+b')

Now, each time you were doing either of these:

foo = s.recv(80)
s.send(bar)

… instead do these:

foo = f.readline().strip()
f.write(bar + '\n')

One last problem that isn't affecting you, but should be fixed:

Calling encode and decode with no argument is almost always a bad idea, especially with network bytes. You're asking Python to decode the data with whatever happens to be in sys.getdefaultencoding() . Can you be sure that the default encoding is the same on the client and server? Can you be sure that it can handle anything the user might type? On a typical Windows machine, it may be something like 'cp1252' , meaning that if the user types a Chinese character, the client will quit with a UnicodeError , which isn't very user-friendly. The right thing to do is to explicitly use 'utf-8' . (Which means your protocol is now "All messages are in UTF-8, and end with a newline.")

If you're using makefile as suggested above, you can solve this even more easily by letting the file object do the encoding for you. Just do this:

f = s.makefile('r+', encoding='utf-8')

Then you can leave out all the decode and encode calls.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM