解决java socket在传输汉字时出现截断导致乱码的问题
解决java socket在传输汉字时出现截断导致乱码的问题
当使用socket进行TCP数据传输时,传输的字符串会编码成字节数组,当采用utf8编码时,数字与字母长度为1个字节,而汉字一般为3个字节。这里参考
字符集之在UTF-8中,一个汉字为什么需要三个字节? - 苦涩的茶 - 博客园 (cnblogs.com)
如果传输的字符串是数字,字符和汉字混杂。在数据的接收端,每次调用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在传输汉字时出现截断导致乱码的问题的更多相关文章
- java socket通信-传输文件图片--传输图片
ClientTcpSend.java client发送类 package com.yjf.test; import java.io.DataOutputStream; import java.io ...
- 解决java web中safari浏览器下载后文件中文乱码问题
解决java web中safari浏览器下载后文件中文乱码问题 String fileName = "测试文件.doc"; String userAgent = request.g ...
- java socket 网络通信 指定端口的监听 多线程 乱码
Java Socket编程 对于Java Socket编程而言,有两个概念,一个是ServerSocket,一个是Socket.服务端和客户端之间通过Socket建立连接,之后它们就可以进行通信了.首 ...
- java socket之传输实体类对象
一.TCP编程 TCP协议是面向连接的.可靠地.有序的,以字节流的方式发送数据.java实现TCP通信依靠2个类:客户端的Socket类和服务器端的ServerSocket类. 基于TCP通信 ...
- Java socket字节流传输的示例
服务端server端: package com.yuan.socket; import java.io.*; import java.net.ServerSocket; import java.net ...
- 解决 java循环中使用 Map时 在put值时value值被覆盖的问题
其实很简单,只需要把容器换成list 然后在循环中,每次循环末尾map = new HashMap() 或者直接在循环中一开始就实例化hashmap(Map map = new HashMap();) ...
- 解决java中ZipFile解压缩时候的中文路径和乱码问题
JAVA中对jar文件或zip文件解压的时候,能够使用JDK内置的API:JarFile和ZipFile,在windows下解压这2种格式文件的时候,常常报下面错误: Exception in thr ...
- socket 发送字符串0x00时被截断
发送数据如下: aa 02 02 00 00 00 6f 6b 02 00 00 00 55 数据是以字符数组的形式(char msg[])存储发送的,send时发送长度填写的strlen(msg), ...
- ASP.NET开发在JavaScript有中文汉字时出现乱码时简单有效的解决
一般情况在使用ASP.NET开发使用JavaScript有中文汉字时不会出现乱码情况,比如:alert('您看到我了吗?');这样直接输入中文汉字的代码中是不会出现乱码的,如果出现了,一是检查Web. ...
随机推荐
- 还不懂 redis 持久化?看看这个
Redis 是一个内存数据库,为了保证数据不丢失,必须把数据保存到磁盘,这就叫做持久化. Redis 有两种持久化方法: RDB 方式以及 AOF 方式 RDB 持久化 前言 RDB持久化把内存中的数 ...
- 初探MFC
MFC MFC(Microsoft Foundation Classes) 是微软基础类库,也就是用c++类将win32API封装起来. 应用程序对象 MFC程序都是以应用程序对象为核心,且程序中只有 ...
- Tomcat&Http协议-授课
1 企业开发简介 1.1 JavaEE规范 JavaEE规范是J2EE规范的新名称,早期被称为J2EE规范,其全称是Java 2 Platform Enterprise Edition,它是由SUN公 ...
- [c++] 分号的使用
加分号的情况: 语句结束加分号(否则编译器不知道在哪里结束语句,编译器不识别换行,写代码时换行和退格只是为了看着舒服,但本质上代码是写给编译器看的) 声明语句后加分号(也是一种语句) 结构体.类定义后 ...
- CSS变量和浏览器前缀
一.CSS变量 CSS变量是CSS的新特性,大多数浏览器都实现了这个功能,使用CSS变量有利代码复用,而且当我们修改变量值时,所有引用该变量的属性都会发生改变. 定义变量后可以有两种使用方法,第一种时 ...
- 列出系统上的存储库,状态是enabled [root@blog ~]# dnf repolist
DNF 和 YUM 均是 rpm 软件包管理工具,但是 DFN 替代 YUM 的说法由来已久,因为 YUM 包管理工具有一些问题长期得不到解决. 这些问题包括性能低下.内存占用高以及依赖包解决方案不佳 ...
- [ML] 高德软件的路径规划原理
路径规划 Dijkstra s:起点:S:已知到起点最短路径的点:U:未知到起点最短路径的点 Step 1:S中只有起点s,从U中找出路径最短的 Step 2:更新U中的顶点和顶点对应的路径 重复St ...
- centos保存rpm到本地以及使用yum完全卸载软件包
目录 保存安装的rpm到本地 方法一: 方法二(推荐): yum卸载软件包包括依赖 保存安装的rpm到本地 方法一: [root@ServerA ~]# vim /etc/yum.conf [main ...
- gitlab的CI/CD实现
环境准备: gitlab账号公网账号:代码仓库和编译器 目标机:装有docker和gitlab-runner环境的服务器(Linux或类unix机器,我使用的时centos 项目代码:testgola ...
- 047.Python前端html
一 HTTP协议 1.1 HTTP请求 URL: 协议/IP:端口/路径?GET参数 基于请求响应 请求协议格式 GET URL路径?a=1&b=2 HTTP # 请求首行 user-age ...