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.