none
TCP/IPのソケット通信を使った2byte文字の送受信方法について RRS feed

  • 質問

  • Visual Basic 2005でソケット通信を行うクライアント/サーバプログラムを作ろうとしています。

    クライアントで読み出したファイル情報(テキスト)をサーバに転送してダイアログのテキストボックス上に表示するものです。

     

    実際動かしてみると半角(1byte)文字は正常にサーバに表示されますが、日本語(2byte)文字は"??"など文字化けして表示できませんでした。恐らく文字コードの設定が問題だと思われるのですが、送受信側それぞれでEncodingの記述を色々変えても解決出来なかったので皆さんのお知恵を拝借出来ればと思います。

     

    なお読み込むファイルのコードをShift-jisやUnicodeなどに変えても現象は変わりませんでした。

     

    ' ### クライアント側 ###

      ' ネットワークストリーム定義
        Private objNetStream As System.Net.Sockets.NetworkStream
        ' TCPクライアントオブジェクト設定
        Private objTcpClient As System.Net.Sockets.TcpClient

      ' TCPクライアントオブジェクト設定
        objTcpClient = New System.Net.Sockets.TcpClient

      ' ファイル転送

     private sub XXX()

         Dim bytSendBuffer As Byte()
            With objTcpClient
                Try
                    'リモートホストと接続します。
                    objTcpClient.Connect(SendMachineName.Text, SendMachinePort.Text)
                    ' ネットワークストリーム取得
                    objNetStream = .GetStream

                    With objNetStream
                        'データをリモートホストへ送信します(VB2005は内部コードがUniCodeなのでASCIIコードに変換する必要あり)
                        'bytSendBuffer = System.Text.Encoding.Default.GetBytes(TextBox1.Text)
                        bytSendBuffer = System.Text.Encoding.ASCII.GetBytes(TextBox1.Text)

                        .Write(bytSendBuffer, 0, bytSendBuffer.Length)

                    End With
                Catch Ex As Exception
                    'エラーメッセージをメッセージボックスで表示します。
                    MsgBox(Ex.Message)
                End Try

                'TCP接続を終了します。
                .Close()
            End With

        End Sub

     

    ' ### サーバ側 ###

        Private Sub XXX()
            Dim bytReceiveBuffer(255) As Byte
            Dim intReceiveLength As Integer
            Dim objNetworkStream As System.Net.Sockets.NetworkStream
            Dim objTcpClient As System.Net.Sockets.TcpClient
            Dim strReceivedData As String

            strReceivedData = ""
            With objTcpListener
                '保留中の接続要求がない場合はプロシージャを抜けます。
                If .Pending = False Then
                    Exit Sub
                End If

                'データの送受信に使用できるTcpクライアントを取得します。
                objTcpClient = .AcceptTcpClient

                With objTcpClient
                    'データを送受信するために使用するストリームを取得します。
                    objNetworkStream = .GetStream

                    Try
                        With objNetworkStream
                            Do
                                If .DataAvailable = True Then
                                    'TCPクライアントから送信されたデータを取得します。
                                    intReceiveLength = .Read(bytReceiveBuffer, 0, bytReceiveBuffer.Length)
                                    'strReceivedData &= System.Text.Encoding.Default.GetString(bytReceiveBuffer).Substring(0, intReceiveLength)
                                    strReceivedData &= System.Text.Encoding.ASCII.GetString(bytReceiveBuffer, 0, intReceiveLength)
                                    '.Substring(0, intReceiveLength)
                                    'strReceivedData &= System.Text.Encoding.Unicode.GetString(bytReceiveBuffer).Substring(0, intReceiveLength)
                                ElseIf Not strReceivedData Is Nothing Then
                                    ' 取得データを画面表示
                                    ReceiveData.Text = strReceivedData
                                    Exit Do
                                End If
                            Loop
                        End With

                    Catch Ex As Exception
                        'エラーメッセージをメッセージボックスで表示します。
                        MsgBox(Ex.Message)
                    End Try

                    'TCP接続を終了します。
                    .Close()
                End With
            End With

        End Sub

    また参考にMicrosoftの下記サポートページにあるコードもそのままビルドして日本語送信できるか確認しましたが、やはり文字化けしました。

    http://support.microsoft.com/kb/821768/ja

     

    2007年6月4日 6:30

すべての返信

  • 済みません。自己レスです。

     

    クライアントがサーバへ転送するデータは、ファイルから読み込んだテキストデータを一回ダイアログのテキストボックスに入れてから、テキストボックスの中身を転送(Write)する仕様になっています。

     

     

    2007年6月4日 6:54
  • とりあえず、

    • クライアントとサーバはエンコーディングを同一にする必要があります。クライアントが Shift_JIS のバイト列を送って、それをサーバで Unicode(UTF-16) として読もうとしても、当然 Unicode(UTF-16) としては意味不明になります。
    • Encoding.ASCII は文字通り ASCII コードしか扱いません。この場合、ASCII コードと言うのは &H00 から &H7F までの値で、その中に日本語は含まれません(詳しくは ASCII コード表をご覧ください)。日本語をやり取りするには日本語をサポートしているエンコーディングを使用する必要があります。
    • StreamWriter / StreamReader を使えば文字列の処理が簡単かもしれません。
    • 読み込むファイルのコードを云々って、ひょっとしてファイルのエンコーディングは事前に把握できない(決め撃ちできない)んでしょうか?
    2007年6月4日 7:17
  • とりあえずそのサイトにあるサンプルを次のように改造し、実行してみてください。

    1, [クライアント] "Is anybody listening..." のところを、適当な日本語にする。

    2, [サーバー] "Successfully connected to TCP server." のところを、適当な日本語にする。

    3, [両方] 合計 4 つある「 Encoding.ASCII 」を、すべて「 Encoding.Default 」にする。或いは Encoding.Unicode でもよい。

     

    ところで念の為に伺いますが、(必ずしも)ASCII = Default ではないということはご存知でしょうか。

    2007年6月4日 10:49
  • Hongliang

     

    SHIROKIです。コメントありがとうございます。

     

    エンコード形式におけるASCII指定を行った訳は、ftpにおける転送方式にASCII/Binaryがあり、ftpでテキストファイルを転送する際、ASCII指定をなんとなく使っていた覚えがあったので、socketにおける転送もエンコードでASCIIを指定すれば何とかなるかと思っていましたが、よくよく考えれば全くの勘違いだったようです。

     

    転送対象のファイルの文字コードは今のところShift-jisですが、コードに依存しない実装もしたいと考えております。

     

    クライアント/サーバ両方のエンコーディング指定でDefaultを指定した結果、正常に日本語も送受信できるようになりました。

     

    教えていただいたStreamWriter / StreamReader も使い方を確認して、実装してみたいと思います。

     

    ありがとうございました。

    2007年6月5日 0:43
  •  Abstract

     

    コメントありがとうございます。

     

    エンコードの指定でDefaultはシステムの現在のエンコードで、ASCIIとは必ずしも一致しないことは認識していましたが、使い方が間違っていたようです。

     

    Microsoftのサンプルプログラム及び私の投稿したプログラムのエンコーディングをDefaultにした結果、正常に日本語が送受信できることが確認できました。ありがとうございました。

     

    2007年6月5日 0:53