解决java socket在传输汉字时出现截断导致乱码的问题

当使用socket进行TCP数据传输时,传输的字符串会编码成字节数组,当采用utf8编码时,数字与字母长度为1个字节,而汉字一般为3个字节。这里参考

字符集之在UTF-8中,一个汉字为什么需要三个字节? - 苦涩的茶 - 博客园 (cnblogs.com)

UTF-8 往事 (taoshu.in)

如果传输的字符串是数字,字符和汉字混杂。在数据的接收端,每次调用read方法接收的byte数组的长度是一定的,由于数字,字母和汉字对应的utf8编码长度不同,可能会导致末尾的汉字被截断。举个例子:假定接收端每次调用read方法读取的byte数组长度为20。而发送短发送的字符串为"Hello World! 你好中国!",转换为byte数组为

[0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x20, 0xE4, 0xBD, 0xA0, 0xE5, 0xA5, 0xBD, 0xE4, 0xB8, 0xAD, 0xE5, 0x9B, 0xBD, 0x21]

在接收端第一次读取的byte数组长度为20,对应的byte数组为

[0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x20, 0xE4, 0xBD, 0xA0,0xE5, 0xA5, 0xBD, 0xE4]

转换为字符变成了"Hello World! 你好�",最后一个字符出现了乱码。这是因为前19个字节(英文空格加标点共13个字节,前两个汉字占六个字节)转换成了字符串"Hello World! 你好",最后一个字节对应着字符"中"的三个字节[0xE4, 0xB8, 0xAD]中的第一个字节0xE4。但是这个一个字节(首位为1没有对应的单字节字符)是无法转换为可见的字符的。这里就是出现了隔断。"中"的剩余两个字节为下一个read读取得到的字节数组的前两两个字节。

为了能够解决截断问题,我们需要判断接收到的字节数组的最后两个字节是否为被截断的汉字字符的对应的字节。

为了解决这个问题,首先了解一个汉字字符在UTF-8编码中的格式。基本上常见的汉字字符在UTF-8编码中都是三个字节。在UTF-8编码方案中,对三字节编码的每个字节都做了规定:

如果是三个字节编码的话,那么第一个字节的前三位为111,第四位为0,剩余的两个字节的前两位都为10

比如汉字"中",对应的三个字节用二进制可以表示为:[1110 0100, 1011 1000, 1010 1101]

满足UTF-8编码的要求。

如何根据编码格式来判断得到的byte数组的最后一个或者两个字节是被截断的呢。

我们将byte数组的最后两个字节定义为firstByte和secondByte,分别对应着导数第二个字节和倒数第一个字节。

情况1:

如果倒数第一个字节符合1110 xxxx格式,说明这个字节对应着汉字字符的第一个字节,剩余的两个字节在下个被接收的byte数组中,发生了截断。我们需要暂存最后一个字节secondByte,与下面一个byte数组的前两个字节组合在一起解析出汉字。

情况2:

如果倒数第二个字节的二进制符合1110 xxxx格式,那就说明这个字节对应着汉字字符的第一个字节,最后一个字节对应汉字字符的第二个字节,第三个字节为下个被接收的byte数组第一个字节,发生了截断。这种情况需要将byte数组的最后两个字符保存起来,与下面一个byte数组的第一个字节结合起来才能解析出对应的汉字。

对于如何判断一个字节是否符合1110 xxxx格式,这里我们采用掩码的方式,保留firstByte的前四位,屏蔽后四位(将后四位置零)。

判断 firstByte & 11100000 == 11100000是否成立,如果成立对应第一种情况,否则

判断secondByte & 11100000 == 11100000是否成立,成立则对应第二种情况

解决java socket在传输汉字时出现截断导致乱码的问题的更多相关文章

  1. java socket通信-传输文件图片--传输图片

    ClientTcpSend.java   client发送类 package com.yjf.test; import java.io.DataOutputStream; import java.io ...

  2. 解决java web中safari浏览器下载后文件中文乱码问题

    解决java web中safari浏览器下载后文件中文乱码问题 String fileName = "测试文件.doc"; String userAgent = request.g ...

  3. java socket 网络通信 指定端口的监听 多线程 乱码

    Java Socket编程 对于Java Socket编程而言,有两个概念,一个是ServerSocket,一个是Socket.服务端和客户端之间通过Socket建立连接,之后它们就可以进行通信了.首 ...

  4. java socket之传输实体类对象

    一.TCP编程     TCP协议是面向连接的.可靠地.有序的,以字节流的方式发送数据.java实现TCP通信依靠2个类:客户端的Socket类和服务器端的ServerSocket类. 基于TCP通信 ...

  5. Java socket字节流传输的示例

    服务端server端: package com.yuan.socket; import java.io.*; import java.net.ServerSocket; import java.net ...

  6. 解决 java循环中使用 Map时 在put值时value值被覆盖的问题

    其实很简单,只需要把容器换成list 然后在循环中,每次循环末尾map = new HashMap() 或者直接在循环中一开始就实例化hashmap(Map map = new HashMap();) ...

  7. 解决java中ZipFile解压缩时候的中文路径和乱码问题

    JAVA中对jar文件或zip文件解压的时候,能够使用JDK内置的API:JarFile和ZipFile,在windows下解压这2种格式文件的时候,常常报下面错误: Exception in thr ...

  8. socket 发送字符串0x00时被截断

    发送数据如下: aa 02 02 00 00 00 6f 6b 02 00 00 00 55 数据是以字符数组的形式(char msg[])存储发送的,send时发送长度填写的strlen(msg), ...

  9. ASP.NET开发在JavaScript有中文汉字时出现乱码时简单有效的解决

    一般情况在使用ASP.NET开发使用JavaScript有中文汉字时不会出现乱码情况,比如:alert('您看到我了吗?');这样直接输入中文汉字的代码中是不会出现乱码的,如果出现了,一是检查Web. ...

随机推荐

  1. 老板让我重构项目,我想首先应该服务治理---eureka服务治理深入浅出

    目录 什么是服务治理 Eureka调用过程 Eureka单机注册 Eureka 单机启动 单机注册 集群注册 客户调用 Eureka集群注册 idea 如何同一个项目启动多次 Eureka自我保护 为 ...

  2. getInstance()得理解

    使用getInstance()方法的原因及作用 https://www.cnblogs.com/roadone/p/7977544.html 使用getInstance()方法的原因及作用 https ...

  3. [Qt] 事件机制(二)

    在samp4_1中加一个小功能,点击右上角关闭按钮时,弹出"确认是否关闭"的消息框.如果点"yes"则关闭,如果点"No"则不关闭 在wid ...

  4. echo "This is line $LINENO"返回行号

    echo "This is line $LINENO"返回行号 LINENO 变量LINENO返回它在脚本里面的行号. #!/bin/bash echo "This is ...

  5. Linux基本原则

    Bash特性 Shell shell(外壳),广义的shell可以理解为是用户的工作环境,在windows看来桌面就是一个shell,在linux看来终端就是shell 常见的shell有两种,一种是 ...

  6. nginx location标签的匹配规则

    location的匹配 匹配符 匹配规则 优先级 = 精确匹配 1 ^~ 以某个字符串开头 2 ~ 区分大小写的正则匹配 3 ~* 不区分大小写的正则匹配 4 !~ 区分大小写不匹配的正则 5 !~* ...

  7. ArcGIS10从入门到精通系列实验图文教程(附配套实验数据持续更新)

    @ 目录 1. 专栏简介 2. 专栏地址 3. 专栏目录 1. 专栏简介 本教程<ArcGIS从入门到精通系列实验教程>内容包括:ArcGIS平台简介.ArcGIS应用基础.空间数据的采集 ...

  8. githubssh配置

  9. GO学习-(34) Go实现日志收集系统3

    Go实现日志收集系统3   再次整理了一下这个日志收集系统的框,如下图 这次要实现的代码的整体逻辑为: 完整代码地址为: etcd介绍 高可用的分布式key-value存储,可以用于配置共享和服务发现 ...

  10. TheSuperego 实验六 团队作业3:项目需求分析与原型设计

    项目 内容 课程班级博客链接 班级博客 这个作业要求链接 作业要求 团队名称 TheSuperego 团队成员分工描述 杨丽霞:组织QQ会议,合理明确组内分工,推进任务,实施关于我们原型设计陈来弟:负 ...