2017-01-10 12 views
1

私はPythonでオンラインの複数プレーヤーコンソールゲームを作成しています。サーバーはPython 3.0を使用し、クライアントはPython 2.7を使用します(私は自分のスマートフォンを使用したいので、Python 2.7しか見つけることができません)。しかし、私はサーバとクライアントの間の文字列のエンコーディングを変換するのに問題があります。Python 3.0で文字列をエンコードし、それをPython 2.7で正しくデコードする方法

ソケット接続から文字列を送受信するには、sendDatareceiveDataの2つの関数を書いています。

UnicodeDecodeError: 'utf8' codec can't decode bytes in position 0-1: unexpected end of data

私は両方で両側にencode('utf-8')またはdecode*('utf-8')を試してみました:問題は、私は、サーバー側で「UTF-8」で文字列你好をエンコードし、クライアント側でそれをデコードしたときに、私はクライアント上でこのエラーを得たことですどちらも機能していません。私もpickleを使用しようとしましたが、クライアントでこのエラーが発生しました:

ValueError: unsupported pickle protocol: 3

文字列をエンコードしてデコードする必要がありますか?ここで

は(Pythonの3.0、datatrans.py)サーバーのための私のコードです:サーバーの

def sendData(sock, data): 
    ''' 
    Send string through socket. 
    ''' 
    sock.send(struct.pack('Q', len(data))) 
    sock.send(bytes(data.encode('utf-8'))) # This might be the cause of the error 

def receiveData(sock): 
    ''' 
    Receive object from socket. 
    ''' 
    lengthLeft = struct.unpack('Q', sock.recv(struct.calcsize('Q')))[0] 
    data = bytes() 
    while lengthLeft > 0: 
     block = sock.recv(lengthLeft) 
     data += block 
     lengthLeft -= len(block) 
    return str(data) 

メインスクリプト(Pythonの3.0):

import socket 
import threading 
import socket 
from datatrans import sendData, receiveData 
import time 

port = int(input('Listen on port:')) 

def log(string): 
    return '[%s]%s' % (str(time), string) 

def handleRequest(sock): 
    sendData(sock, '你好') 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.bind(('0.0.0.0', port)) 
s.listen(5) 

try: 
    while True: 
     sock, addr = s.accept() 
     print(log('%s entered the game' % str(addr))) 
     #print sock.recv(1000) 
     threading.Thread(target = handleRequest, args = (sock,)).start() 
finally: 
    s.close() 

クライアントのための私のコードは、このですsendDatareceiveDataで(Pythonの2.7)を少し変更:

# -*- coding: UTF-8 -*- 
import socket 
import struct 

def sendData(sock, data): 
    ''' 
    Send string through socket. 
    ''' 
    sock.send(struct.pack('Q', len(data))) 
    sock.send(data) 

def receiveData(sock): 
    ''' 
    Receive object from socket. 
    ''' 
    lengthLeft = struct.unpack('Q', sock.recv(struct.calcsize('Q')))[0] 
    data = '' 
    while lengthLeft > 0: 
     block = sock.recv(lengthLeft) 
     data += block 
     lengthLeft -= len(block) 
    return data.decode('utf-8') # Error comes from here 

while True: 
    try: 
     ip = raw_input('Sever IP:') 
     port = int(raw_input('Port:')) 

     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     s.connect((ip, port)) 
    except socket.error as error: 
     print('Error while connecting') 
     print(error) 
     print('') 
    else: 
     break 

while True: 
    print(receiveData(s)) 

また、私はWHを思ったんだけど私はクライアントからサーバーにユーザーが入力した文字列を送信するときにサーバーがエンコードエラーについて不平を言わないようにする必要がありますか? Python 2.7は、異なるシステムで異なるエンコーディングを使用しているので、今私はそれをどのように扱うべきかについて考えていません。ありがとう!

答えて

0

Python2プログラムがバイト文字列を常に処理している(つまり、Unicode文字列ではありません)が、ペイロードではエラーが発生した場所をデコードしようとする1つの問題があります。

小さなアプリケーションの場合は、デコードステップをスキップして、クライアントアプリケーションを常にutf-8でエンコードされたバイトストリングに対応するようにプログラミングしてください。 (しかし、入力を取得してそこにネットワークを介して送信する以外にテキストを処理しなければならない場合は実行できません)。

これは、サーバーがデータを正しくエンコードしているので、UnidodeDecodeエラーの原因ではなく、二重エンコードしてもこの特定のエラーは発生しません。

サーバ側では、文字列の長さpré-encodingを計算し、それをUTF-8にエンコードします。あなたの例で私たちに見せてくれるクラスのクラスでは、utf-8は1文字につき4バイトまでかかります。

したがって、長さ「2」の文字列を送信し、8バイトを送信するペイロードを作成します。実際に文字を元に戻すには、テキストデコーダで4個必要になります。

ちょうどこの書き換え:これに

def sendData(sock, data): 
    ''' 
    Send string through socket. 
    ''' 
    sock.send(struct.pack('Q', len(data))) 
    sock.send(bytes(data.encode('utf-8'))) 

def sendData(sock, data): 
    ''' 
    Send string through socket. 
    ''' 
    encoded_data = data.encode('utf-8') 
    sock.send(struct.pack('Q', len(encoded_data))) 
    sock.send(bytes(encoded_data)) 

をそして、あなたがこの主なエラーを排除する必要があります。

また、サーバーサイト受信者関数の最後の行は、 return str(data)とすることはできません。代わりにreturn data.decode('utf-8')にしてください。

関連する問題