2

私は Python 3.3 が初めてで、ソケットを使用してちょっとした推測ゲームを書き始めています。ただし、コードの前の方に同様の行があるためValueError: invalid literal for int() with base 10: ''
、行にこのエラーが発生する理由がわかりません。currentGuess = int(currentGuess)誰かが私を助けることができれば、私はとても感謝しています. これが私のサーバーとクライアントのコードです。同様の問題を持つ他のソリューションを見てきましたが、私のために働くことはできません。

サーバ

    #!/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()

クライアント

    #!/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()
4

2 に答える 2

1

int空の文字列を呼び出そうとすると、次のエラーが発生します。

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

これが意味することは、次の場合です。

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

currentGuessに設定されてい''ます。つまりs.recv(1024)、空の文字列を返しています。これは、接続が閉じられたときにのみ発生するため、クライアントがサーバーへのデータ送信を停止したことを意味します。

于 2013-10-23T20:32:41.137 に答える
1

から空の文字列を返すというs.recv()ことは、相手側が呼び出した、closeまたはshutdown接続していることを意味します (または、他の方法で中断されました。相手側が終了したか、誰かがイーサネット コードを引き抜いた)。

サーバーコードを見ると、3回の推測が必要だと言うと、recv3回試行します...しかし、クライアントは1send回しか試行せず、その後close接続します. つまり、サーバー上の nextrecvは空の文字列を返します。これはまさにあなたが見ているものです。

これを修正するには、相手側が期待するだけの数の推測を送信する必要があります。このようなもの:

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

その間、この特定の問題は発生していませんが、コードは確実に動作しません。ソケットはバイト ストリームであり、メッセージ ストリームではありません。それぞれが反対側のsendと一致するという保証はありません。recvrecv、 の半分sendまたは 2sendつがまとめられている場合があります。一部のプラットフォームでは、localhost を使用して小さなメッセージを送信し、送信速度が速すぎない場合、常にすべてがうまくいきます。他のプラットフォームでは、ほとんどの場合は機能しますが、時々機能しないことがあります。他のものでは、頻繁に失敗します。

その上、ドキュメントで説明sendされているように、文字列全体を送信することが保証されることはありません。そのため、実際に送信されたバイト数が返されます。を使用するだけでこの問題を解決できますがsendall、それでは他の問題は解決しません。

プロトコルを設計して実装することにより、TCP バイト ストリームの上にメッセージ ストリームを構築する必要があります。恐ろしく聞こえるかもしれませんが、「すべてのメッセージは改行で終わる」という非常に単純なプロトコルはmakefile、次のようにメソッドを使用するだけで実装できます。

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

さて、次のいずれかを実行するたびに:

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

…代わりに次のようにします。

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

影響はありませんが、修正する必要がある最後の問題:

encode引数なしで呼び出すdecodeことは、ほとんどの場合、特にネットワーク バイトの場合は悪い考えです。Python に、たまたま にあるものでデータをデコードするように要求していますsys.getdefaultencoding()。デフォルトのエンコーディングがクライアントとサーバーで同じであることを確認できますか? ユーザーが入力する可能性のあるものをすべて処理できると確信できますか? 典型的な Windows マシンでは、これは のようなもの'cp1252'で、ユーザーが漢字を入力すると、クライアントは で終了しますがUnicodeError、これはあまりユーザーフレンドリーではありません。正しいことは、明示的に使用すること'utf-8'です。(これは、プロトコルが「すべてのメッセージは UTF-8 であり、改行で終わる」ことを意味します。)

上記のように使用makefileしている場合は、ファイル オブジェクトにエンコードを行わせることで、これをさらに簡単に解決できます。これを行うだけです:

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

次に、すべてのdecodeandencode呼び出しを省略できます。

于 2013-10-23T20:33:12.123 に答える