通过TcpClient发送包含特殊字符的字符串(byte[])

8
我正在尝试通过TcpClient(byte [])发送包含特殊字符的字符串。这是一个示例:
  • 客户端在文本框中输入“amé”
  • 客户端使用某种编码将字符串转换为byte [](我尝试过所有预定义的加上一些如“iso-8859-1”的编码)
  • 客户端通过TCP发送byte []
  • 服务器接收并使用相同的编码重新转换字符串(输出到列表框)

编辑:

我忘记提到结果字符串是“am?”。

编辑2(按要求,这里是一些代码):

@ DJKRAZE这是一小段代码:

byte[] buffer = Encoding.ASCII.GetBytes("amé");
(TcpClient)server.Client.Send(buffer);

在服务器端:

byte[] buffer = new byte[1024];
Client.Recieve(buffer);
string message = Encoding.ASCII.GetString(buffer);
ListBox1.Items.Add(message);

在列表框中显示的字符串是 "am?"

=== 解决方案 ===

Encoding encoding = Encoding.GetEncoding("iso-8859-1");
byte[] message = encoding.GetBytes("babé");

更新:

只需使用Encoding.Utf8.GetBytes("ééé");即可完美解决。


Philippe,你有现成的代码吗?为什么人们在线上问问题时期望我们知道他们在谈论什么?我们无法看到你正在做什么,也不知道你的代码长什么样子。因此,请发布你正在使用的内容。 - MethodMan
@DJKRAZE 这里有一些代码:byte[] buffer = Encoding.ASCII.GetBytes("amé"); (TcpClient)server.Client.Send(buffer);在服务器端:byte[] buffer = new byte[1024]; Client.Recieve(buffer); string message = Encoding.ASCII.GetString(buffer); ListBox1.Items.Add(message);在列表框中出现的字符串是“am?” - Philippe Paré
2
ASCII在这里不起作用 - 它不支持带重音的字符。请尝试使用UTF-8。 - 500 - Internal Server Error
@500-内部服务器错误,尝试使用了所有预定义的选项,包括utf-8.. :S - Philippe Paré
如果去掉中间人(套接字连接),它是否能与UTF-8一起工作? - 500 - Internal Server Error
3个回答

11

我觉得回答问题从来都不会太迟,希望有人能在这里找到答案。

C#使用16位字符,ASCII将其截断为8位以适应一个字节。经过一些研究,我发现UTF-8是处理特殊字符的最佳编码方式。

//data to send via TCP or any stream/file
byte[] string_to_send = UTF8Encoding.UTF8.GetBytes("amé");

//when receiving, pass the array in this to get the string back
string received_string = UTF8Encoding.UTF8.GetString(message_to_send);

1
你在这里说过你已经尝试过了,但是没有成功。有什么改变吗? - Scott Chamberlain
C#的char数据类型可以容纳一个UTF-16代码单元,其中一个或两个代码单元可以编码一个Unicode代码点。UTF-8将一个Unicode代码点编码为1到4个字节。只要在两端使用相同的编码方式且编码方式不会因无法表示所需字符而导致数据丢失,就可以使用任何一种编码方式。如果无法表示,则GetBytes()将采取某些操作。标准操作是用"?"替换;抛出异常也很常见;截断不常见,但如果您想引起数据损坏,可以这样编码。 - Tom Blodget
Scott,显然我对代码还有一些其他的问题。当两边都使用 UTF-8 编码时,它能够完美地工作。我更新了问题,以免让人们误解我说 UTF-8 不起作用。 - Philippe Paré
汤姆,我的意思是无论C#如何存储字符本身,它都是2个字节,因此ASCII对于像“é”这样的特殊字符没有帮助。 - Philippe Paré
@PhilippeParé,Tom所说的是C#在内部使用UTF-16,其大小可以为2或4个字节。例如,U+1D11EMUSICAL SYMBOL G CLEF)是可表示的,但在内存中它将被表示为四个字节的D8 34 DD 1E - Scott Chamberlain
真有趣!从未见过这种情况,我猜当字符串中只有一个字符使用了如I+1D11E这样的字符时,它会将所有字符存储为4个字节。 - Philippe Paré

5

您的问题似乎在于Encoding.ASCII.GetBytes("amé");Encoding.ASCII.GetString(buffer);两个调用,正如他的评论中暗示的那样出现了“500-内部服务器错误”。

é字符是一个多字节字符,使用UTF-8编码时,其字节序列为C3 A9。当您使用Encoding.ASCII类进行编码和解码时,é字符会被转换为问号,因为它没有直接的ASCII编码。这对于任何没有直接ASCII编码的字符都是正确的。

将您的代码更改为使用Encoding.UTF8.GetBytes()Encoding.UTF8.GetString(),它应该可以为您工作。


0

我不清楚你的问题和错误,但使用Base64String可能会解决问题
类似这样的:

static public string EncodeTo64(string toEncode)
    {
      byte[] toEncodeAsBytes
            = System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
      string returnValue
            = System.Convert.ToBase64String(toEncodeAsBytes);
      return returnValue;
    }

static public string DecodeFrom64(string encodedData)
    {
      byte[] encodedDataAsBytes
          = System.Convert.FromBase64String(encodedData);
      string returnValue =
         System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes);
      return returnValue;
    }

尝试实现了这个,但是不起作用...我收到错误提示说字符串不是base64格式的... - Philippe Paré
1
好的!绕过了这个大问题。我现在正在使用“iso-8859-1”编码。以下是一些代码,供将来有兴趣的人参考。Encoding encoding = Encoding.GetEncoding("iso-8859-1"); byte[] message = encoding.GetBytes("babé");服务器端的结果是:“babé”!无论如何,感谢所有的回答 :) - Philippe Paré

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接