sbf888胜博发MQTT协议的消息类型, 可以如何分类?

( sbf888胜博发 )

    public final static int MQTT_CONNECT = 1;        //请求连接
    public final static int MQTT_CONNACK = 2;        //请求应答
    public final static int MQTT_PUBLISH = 3;        //发布消息
    public final static int MQTT_PUBACK  = 4;        //发布应答
    public final static int MQTT_PUBREC  = 5;        //发布已接收,保证传递1
    public final static int MQTT_PUBREL  = 6;        //发布释放,保证传递2
    public final static int MQTT_PUBCOMP = 7;        //发布完成,保证传递3
    public final static int MQTT_SUBSCRIBE = 8;         //订阅请求
    public final static int MQTT_SUBACK = 9;            //订阅应答
    public final static int MQTT_UNSUBSCRIBE = 10;      //取消订阅
    public final static int MQTT_UNSUBACK = 11;       //取消订阅应答
    public final static int MQTT_PINGREQ = 12;        //ping请求
    public final static int MQTT_PINGRESP = 13;        //ping响应
    public final static int MQTT_DISCONNECT = 14;       //断开连接

第一次接触这种在socket上的编程.目前想实现一个语音分发的功能, 差不多就是群聊吧.
采用的netty, 协议是用的MQTT

我目前想法是在服务器这边定义几个handler(非netty中的handler概念), 这个就对应消息类型的几大类, 比如消息handler, 用户handler, 每种handler可以处理几种消息类型. 但是又不知道如何分类比较合适? 请各位帮忙看看. 或者有更好的思路的,请指教.先谢过了.


1. 首先你列出的是MQTT协议中对于服务器分发消息中的固定报头中对于消息类型的定义。

其实,这在大部分开源实现中是统一的,没有什么实际意义,主要根据这些类型,来做一些业务上的处理。比如,你在接受到请求连接MQTT_CONNECT时候,初始化资源;
在断开连接MQTT_DISCONNECT的时候,做一些扫尾工作,就像在app中发现已经断开连接,就主动推送一个消息给app,告诉app连接已断开,不能发送消息了;

2.真正实现业务上的消息类型,是需要自己自定义的,在payload中,定义消息类型。payload才是真正业务消息实体。
比如,自定义:

{
//文本
  message : 1,
  content : "你好",
  time    : "2016-2-1"
}
{
//图片
  message : 2,
  content : "www.baidu.com/image/img.jpg",
  time    : "2016-2-1"
}

当然,主要根据自己的业务需求,定义需要的消息类型与格式,然后将上面的数据转换为data,将data置于在payload中进行分发。

我也是刚接触MQTT协议不久,,而且做的iOS端的订阅,分发。粗浅理解,提供一个思路,可以互相交流学习。
在github上,我整理了一些材料:https://github.com/wenghengcong/MQTTExplore

(看完/读完)这篇文章有何感想! sbf888胜博发的分享…

www.sbf888.comEclipse:求教单步调试Java

( www.sbf888.com )


启动线程检查是否为零点,如果为零点则执行checkECCNEAlarm()方法
单步调试时如果不为零点,则在checkECCNEAlarm中打上断点一定是进不去的,可不可以在单步调试时强制将

new Datex().isMidnight()

设为true呢?这样就可以直接进断点就不用改代码来调试了,求解

仅修改一次代码,把new Datex().isMidnight()给一个变量,然后判断变量。
调试时候强制修改变量值。

if(!new Datex().isMidnight()){
    checkECCNEAlarm();
}

(看完/读完)这篇文章有何感想! www.sbf888.com的分享…

www.sbf888.com一个错误达到一个峰值后,为什么之后就全都是相同的错误了

( www.sbf888.com )

一个错误达到一个峰值后,为什么之后就全都是相同的错误了,求赐教

没听明白怎么回事,我猜是栈溢出吧?
一直是相同的错误提示有可能就是你在某个函数递归调用了自己然后又没有停止条件导致栈溢出

(看完/读完)这篇文章有何感想! www.sbf888.com的分享…

sbf888胜博发有很多if-else,该如何优化?

( sbf888胜博发 )

这是我重构之后的代码:各位大神看看呢,我一直在纠结设计模式..要疯==

在if 不满足条件时直接return掉,就不用写else了,这样可以减少if的深度
对于你的例子了,如下:

if (!tokenCheck.equals(token)) {
    obj.setStatus();
    obj.setMsg();
    return obj;
}

if (!isContinue) {
    obj.setStatus();
    obj.setMsg();
    return obj;
}

if (action == 20) {
    // TODO
} else if (action == 30) {
    // TODO
}

这样会让代码好看一点.

如果你纠结设计模式的话,可以把“调用系统通知”和”调用短信接口”抽象成策略,实现共同的接口;
每个策略提供一个accept方法用于判断是否接受传入的actionId,如果accept通过,就可调用该策略的execute方法。

List<Strategy> strategys = new ArrayList<>();
strategys.add(new SystemNoticeStrategy());
strategys.add(new MessageStrategy());

for (Strategy stragety : stragetys) {
    if (strategy.accept(actionId)) {
        strategy.execute();
        break;
    }
}

这个的缺点是要遍历list,其实性能开销并不会太大。

也可以把这些strategys放到map里,然后直接根据actionId从map中取出并执行。

这是一种实现思路,可能还会有更好的方式。

这点if else优化个毛线 企业应用那种炒鸡复杂的逻辑都是要跑工作流的 轮不到你业务开发操心
你优化完业务错了就好玩了
唯一一点看着很不爽的 就是你用了一堆println 老老实实找个log4j来用好嘛

复杂一点的应用可以往外甩异常,然后通用的功能,比如鉴权之类,放到拦截器里做,不要放业务里,这样能简洁一点,然而你如果业务就这么复杂优化什么呢

设计模式不是为了模式而模式的,等你哪天上了spring,mybatis这些,想不模式都难
如果再装一点B呢,提示文字要弄到配置里去,或者用i18n来做,每个引用的地方只放对应的id,要不以后改一句话找死你

推荐看 《重构:改善既有代码的设计》这本神书,可以解决代码设计上的很多问题,不仅仅是深层的if-else。

虽然有点答非所问的嫌疑,但冒死也要提交回答!

如果是我的话 我会写一个Map池,存进map里,直接从Map里取

嵌套的 if 可以通过细化成方法来优化

比如你这里

if (tokenCheck.equals(token)) {
    doWork(...);
} else {
    ...
}

void doWork(...) {
    if (isContinue) {
        ...
    } else {
        ....
    }
}

以此类推

你这里应该是说的判断actionId的if太多了吧。

如果每个if后面跟的业务逻辑很复杂你可以用多态来代替if

但是你这里似乎不是很复杂,也没什么大问题

if-eles 和 switch 在本质上没啥区别,如果条件特别多的话有两种方法细分

一种是先分大段,再分小段,比如

int n = id / 50;
switch (n) {
    case 0:
        do0_49(id);
        break;
    case 1:
        do50_100(id);
        break;
    // ....
}

另一种方法就是建表,把所有 id 对应的东西都放在表中,比如 HashTable。
如果是完全连续(或者少数不连接)的情况,就用数组或者 List 解决了。
你的这个问题中,键是 int,值是 String(保存消息文本) 就好,在其它更复杂的情况下,可以保存对象(比如 Listener 对象,或者 Command 对象之类的)

像这种情况,最常见的,也是效率较高的就是做查找表,或者Hash表
即:

建一个表:

Map ActionMap = new HashMap<Integer, String>(){
    {
        put(20, "ddd");
        put(40, "line1\nline2");
    }
};

然后再直接索引输出:

System.out.println(ActoinMap.get(id));

常量+静态数组,写会不会更好呢?

(看完/读完)这篇文章有何感想! sbf888胜博发的分享…

www.sbf888.comjava的字面量的内存是不可变的麽?

( www.sbf888.com )

譬如 

String foo= "a";
String bar= "a";

那么,在上面的这个栗子中,两个”a”本身是统一份内存空间麽?

如果String foo="a" + "b"
如果String bar="ab"

这里是否存在运算,先计算出”a”+”b”的字面量(“ab”),初始化”ab“ 后,接下来的任何

String x="ab",都是对之前”ab”的字面量的引用持有呢?


Update
String foo="a" + "b" 这条语句,假设在之前没有”a”和”b“的init.那么在这里创建了
”a“,”b”,”ab”呢
还是只创建了”ab”呢?

  1. String foo = "a"; String bar = "a";这两个是一份内存空间,都在字符串常量池

  2. String foo="a" + "b",String bar="ab";这两个也是,"a" + "b"在编译期就会被优化为"ab"

  3. String foo="a" + "b"只创建了“ab”,同上

是的,之前定义了String bar=”ab”,后面再定义String x=”ab”,此时bar和x都指向同一个对象。
除非你使用new String(“ab”)。

对于这个问题:
String foo=”a” + “b” 这条语句,假设在之前没有”a”和”b“的init.那么在这里创建了
”a“,”b”,”ab”呢
还是只创建了”ab”呢?
答案肯定是创建了3个字符串对象,”a”,”b”,”ab”。所以频繁的进行字符串拼接操作会浪费内存,需要使用StringBuffer或者StringBuilder来进行拼接操作。

(看完/读完)这篇文章有何感想! www.sbf888.com的分享…

www.sbf888.commimeLimit 限定用户上传的文件类型 无效

( www.sbf888.com )

StringMap putPolicy=new StringMap().put(“mimeLimit”, “image/*”).put(“returnBody”, returnBody);
配置了限制只能为图片类型,但是文本文档一样可以上传

put方法中,指定文件mineType是指什么?

(看完/读完)这篇文章有何感想! www.sbf888.com的分享…

sbf胜博发娱乐城利用POI导出Excel,如果数据量超过Excel支持最大的1048576行,该怎么处理?

( sbf胜博发娱乐城 )

最近做了一个Excel导出,突然想到一个问题,如果在生产上导出的数据量超过了Excel支持的最大行数,怎样处理才是最优的办法?(求学习关键代码)

分sheet,分workbook,还能咋整。。。

(看完/读完)这篇文章有何感想! sbf胜博发娱乐城的分享…

www.sbf888.com[讨论/问答][Java]如何将树形结构转为扁平集合

( www.sbf888.com )

问题就如题。将树形结构转为扁平的集合。
想不用递归。或者其他高性能的实现方式。
最想的就是能用上 J8 最新的 Stream API 。
但是自己咋想也想不到比较靠谱的实现。
这里提供一个借口供大家举例。

class Node {
    private String name;
    private List<Node> children;
    // get set ignore
}

递归遍历转成map就可以了

(看完/读完)这篇文章有何感想! www.sbf888.com的分享…

sbf888胜博发关于java中关闭流疑问

( sbf888胜博发 )

下面这段代码的作用是压缩,会用到ZipOutputStream

    ZipOutputStream zipOutputStream = null;
    try {
      zipOutputStream = new ZipOutputStream(new FileOutputStream(zipPath));
    } catch (FileNotFoundException e) {
        throw new IllegalArgumentException("zipPath error " + "", e);
    } finally {
        if (null != zipOutputStream) {
            try {
                zipOutputStream.close();
            } catch (IOException e) {
                logger.error("", e);
            }
        }
    }

错误放大版1:

    ZipOutputStream zipOutputStream = null;
    try {
        FileOutputStream fileOutputStream =   new FileOutputStream(zipPath);
        throw new RuntimeException();
        zipOutputStream = new ZipOutputStream(fileOutputStream);
    } catch (FileNotFoundException e) {
        throw new IllegalArgumentException("zipPath error " + "", e);
    } finally {
        if (null != zipOutputStream) {
            try {
                zipOutputStream.close();
            } catch (IOException e) {
                logger.error("", e);
            }
        }
    }

错误放大版2:

    ZipOutputStream zipOutputStream = null;
    try {
      zipOutputStream = new ZipOutputStream(new FileOutputStream(zipPath),null);
    } catch (FileNotFoundException e) {
        throw new IllegalArgumentException("zipPath error " + "", e);
    } finally {
        if (null != zipOutputStream) {
            try {
                zipOutputStream.close();
            } catch (IOException e) {
                logger.error("", e);
            }
        }
    }
    

这里我有一个疑问,在new FileOutputStream(zipPath)的过程中如果已经打开了这个文件,但是在new ZipOutputStream过程中出错了,这个时候zipOutputStream并没有创建成功,所以在finally中不会调用close方法,造成的结果就是这个文件不会被关闭。
所以这种关闭方式是不是会有漏洞,还是我的理由有问题?

这个例子有漏洞,不过漏洞不在这里,而是 FileOutputStream
如果 new ZipOutputStream()调用失败,这个构造方法会抛出运行时异常,而且不会关闭传递进来的 FileOutputStream 对象。
由于调用者也不持有该对象的引用,也无法释放资源,会造成打开的文件描述符没有关闭。
如果使用java8的话可以用 try with,或者在finally块里面释放FileOutputStream 对象持有的资源,这样是比较保险的做法。

在这个过程中只会发生FileNotFoundException异常,而此时ZipOutputStream对象还没有创建,没有任何流被打开,所以当然是不需要关闭的。所以这段代码没有问题



    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        Test test = new Test();
        test.test1();
        System.out.println(123);
    }

    public void test1() {
      try {
          ArrayList<Double> al = new ArrayList<Double>();
          for (int i = 0; i < 1000000; i++) {
              for (int j = 0; j < 1000000; j++) {
                  al.add(Math.random());
              }
          }
      } catch (Throwable e) {
          System.out.println("catch");
      } finally {
          System.out.println("finally");
      }
  }

输出:

finally
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.lang.Double.valueOf(Unknown Source)
    at qmk.TestAnything.test1(TestAnything.java:50)
    at qmk.TestAnything.main(TestAnything.java:41)

结论:

发生OutOfMemeoryError时,finally可以执行,但是catchmain方法后面的打印语句都没有执行,虚拟机直接奔溃了。

我之前说发生内存溢出时finally不会执行是不对的,事实表明finally是会执行的,特此更正。

@brayden

解决方法很简单你直接close掉传递的FileOutputStream即可。
这个漏洞是存在的,可以从代码层面解决,这种装饰器模式虽然很好,但是对被装饰的对象管理不当就会出现这种情况。

(看完/读完)这篇文章有何感想! sbf888胜博发的分享…

www.sbf888.comJava问题求指教:boolean[] arr = new boolean[s];

( www.sbf888.com )

数组arr的长度为S,是不是只要在arr数组里面的值都true,然后不再arr里面的数值就为false。是不是我理解的这样?

布尔变量默认初始化值为false,所以题主的arr数组所有元素数值都为false,题主可以把数组打印出来自己验证增加印象。

你只是定义了一个长度为s的数组而已,而且是boolean类型,那么arr中的成员默认将全部是false,希望对你的提问有所帮助。

boolean的默认值是false,你这样没赋值的话应该arr中应该都是false

(看完/读完)这篇文章有何感想! www.sbf888.com的分享…

sbf胜博发娱乐城java的Swing,JTextField充满了整个窗口。

( sbf胜博发娱乐城 )

import java.awt.Dialog;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

public class Client {
    public static void main(String[] args){
    
        JFrame denglu = new JFrame("登陆界面");
        denglu.setVisible(true);
        denglu.setBounds(600, 420, 470, 250);
        JLabel word=new JLabel("欢迎使用,请先登录");
        word.setBounds(141, 30, 180, 30);
        JLabel name=new JLabel("账号");
        name.setBounds(80, 70, 40, 20);
        JLabel password=new JLabel("密码");
        password.setBounds(80, 100, 40, 20);
        JButton xiugaiBut = new JButton("修改密码");
        xiugaiBut.setBounds(80, 130, 100, 20);
        JButton dengluBut = new JButton("登陆");
        dengluBut.setBounds(200, 130, 100, 20);
        JTextField txtZhanghao = new JTextField();
        txtZhanghao.setBounds(150, 70, 140, 20);
        
        
        denglu.setResizable(false);
        JTextField txtPassword = new JTextField();
        txtPassword.setBounds(150, 100, 140, 20);
        denglu.add(word);
        denglu.add(name);
        denglu.add(password);
        denglu.add(xiugaiBut);
        denglu.add(dengluBut);
        denglu.add(txtZhanghao);
        denglu.add(txtPassword);
    }

}


运行结果:![图片描述][1]

第二个输入文本框充满了整个窗口
这是为什么,有什么好的解决办法吗?

需要添加

denglu.setLayout(null);

因为JFrame默认的Layout是BorderLayout,所以跟setBounds没有关系,只支持东南西北中布局方式,如果没有指定方向,控件默认都是添加到中间。

(看完/读完)这篇文章有何感想! sbf胜博发娱乐城的分享…

sbf胜博发娱乐城由java来提供接口的安卓app 改成php的难度大吗是否可行

( sbf胜博发娱乐城 )

基于java开发的app 能改成php的吗
商城类应用要改成php+mysql。是不是相当于重做了。

api用什么语言开发都一样,和哪个平台无关。
改语言的话其实相当于移植,你原来的业务逻辑复杂的话,移植的难度也大。

java用的好好地,为啥非要换成php呢,找不到java的人?
迁移成本是很高的,基本上就是重写,又没有转换工具。

(看完/读完)这篇文章有何感想! sbf胜博发娱乐城的分享…

sbf888胜博发SQL Server 大量Update和Insert操作如何提升性能?

( sbf888胜博发 )

业务是这样的:

每个物品有唯一编号如0011,业务表中需要对物品的每个状态更新进行记录,业务表结构如下:id, item_id, pre_time, cur_time, value(除了id其他都是varchar(20),历史遗留问题)

每次进来一个作业(item_id, this_value, time_now),内存中维护每个item的last_value信息,如果该item的last_value == this_value则对业务表更新,将cur_time更新为time_now。如果该item的last_value != this_value则对业务表进行插入操作,新增一条记录(id++,item_id, pre_time=time_now, cur_time=time_now, value=this_value)

现在的问题是每秒钟需要进行的作业量很多(需要对业务表进行频繁的插入、更新操作),只有id的聚集索引,更新速度非常慢,大概每秒钟只能处理几十个作业,但是每秒钟有1000+的更新

  1. 直接把逻辑写到SqlServer上面去.
    SqlServer是支持复杂语句的, 也就是item_id, this_value, time_now可以当作一个存储过程的参数. 里面写select if update insert之类的

  2. 在逻辑层解决这个问题
    服务启动的时候, 把所有的item_id => (pre_time, cur_time, value)全部load出来, 然后缓存起来. 处理新来的消息的时候, 就知道到底该更新, 还是插入, 最后只需要处理一条SQL语句. 一秒1000+的SQL还是很容易的吧, 用几个Connection就行了.

批处理,不要每次一条数据就去访问数据库,每100条进行一次数据库访问操作

(看完/读完)这篇文章有何感想! sbf888胜博发的分享…

sbf胜博发娱乐城【SOS】nginx无法解析php文件?

( sbf胜博发娱乐城 )

已经在服务器上装了nginx和php,php-fpm(监听9000端口)
可以正常显示html,但是每当输入url打开一个php时,无法正常解析,导致变成下载模式

nginx.conf如下

现在打开php直接变成404…Orz

干脆贴出来吧,估计是这一段的问题,搞了好久都没进展….

location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
}

这样写试一下 用nginx -t命令检查你的nginx配置文件是否有错误
location /index.php {

    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    include        fastcgi_params;

}

我以前也有过,当时是centos6,后来换成7了。
之后绑定好域名就好了

还能显示nginx的画面
问题是我用域名安装源码怎么就显示404
用ip安装弹出php文件的下载,php我也运行了啊。
网站默认主目录我也已经定位到www.38934.tech上面了。
苦恼啊!
2016-10-26 09:33:34
管理员
请您确保以下3个设置:

  1. 域名解析到服务器IP

  2. Nginx网站管理里有配置这个域名

  3. 修改完配置后有重载或重启Nginx
    目前已为你修正配置。

第一步 nginx.conf的配置

location / {
        if (!-e $request_filename) {
             rewrite  ^/(.*)$  /index.php/$1  last;
             break;
        }
    }

    location ~ ^/s-([0-9a-z]+)-(.*) {
        rewrite ^/s-([0-9a-z]+)-(.*) /shtmls/$1/$2 last;
        break;
    }

    location ~ .+\.php($|/) {
        set $script    $uri;
        set $path_info  "/";
        if ($uri ~ "^(.+\.php)(/.+)") {
              set $script     $1;
              set $path_info  $2;
        }

        fastcgi_pass 127.0.0.1:9000;
        include fastcgi_params;
        fastcgi_param PATH_INFO $path_info;
        fastcgi_param SCRIPT_FILENAME  $document_root/$script;
        fastcgi_param SCRIPT_NAME $script;

    }

第二步 sudo vim /etc/php5/fpm/pool.d/www.conf
将 ;listen = /var/run/php5-fpm.sock
改成 listen = 127.0.0.1:9000

你的代码直接放在/root里么?你改过之后的完成配置也发一下吧。

(看完/读完)这篇文章有何感想! sbf胜博发娱乐城的分享…

sbf胜博发娱乐城如何在自己的项目中实现word在线编辑

( sbf胜博发娱乐城 )

希望能在自己(公司)的项目中实现word在线编辑,感觉无从下手

(不好意思,没说清楚,我补充一下:比如我上传了一份word,然后能在线编辑这个word文件,编辑之后能保存)

谢邀~
富文本编辑器
http://summernote.org/

你可以使用百度的ueditor
http://ueditor.baidu.com/webs…

如果不考虑富文本编辑器的话,硬要实现office系列的在线编辑。

你大概有以下几条路走:
1、只考虑IE,用专有ActiveX插件,实现浏览器里面编辑office文档。https://github.com/stone0090/…
2、现代浏览器,接入在线的office online 。

不要说在线 Word 编辑,就是在线 Word 阅读都已经很不容易了,这个功能太专业了。

网上能搜到一些阅读组件,大部分是收费的,比如永中的高清服务器版本收费大概是80K。

另外,你可以去看看 Open Office 有没有提供相关的组件。Open Office 一直是开源的 Office 解决方案。

(看完/读完)这篇文章有何感想! sbf胜博发娱乐城的分享…

www.sbf888.comphp中的字符编码

( www.sbf888.com )

$str1 = "\xe4\xb8\xad";

$str2 = '\xe4\xb8\xad';

$str3 = '中';

能否详细解释一下三者的区别,是否可以相互转化

第一次在segmentfault上回答问题。。

PHP字符串变量,双引号和单引号的意义是不同的

使用双引号时会转义 单引号时不转义
使用双引号时,$xxxx文本会被相应变量的值替换,单引号没有这个效果

Eg.

$abc='123';
echo "$abc"; //这样会输出123
echo '$abc'; //这样会输出$abc
echo "\n"; //这样会输出一个换行符
echo '\n'; //这样会输出\n两个字符(一个斜杠一个n)

回到问题,
“中”这个汉字在UTF-8的16进制编码是0xe4,0xb8,0xad
因此在双引号字符串中,会被转义为 “中” x开头表示这是一个以十六进制表达的字符,就和HTML中&xe4; 一样
单引号字符串中,直接输出xe4xb8xad

如果你的环境编码是在UTF-8下面, str1和str3等价, 如果直接echo, 都会输出”中”, 如果是二进制层面三个字节比较, 也是完全相等, PHP中的字符串就是直接本地编码二进制存储的

如果你的环境编码是非UTF-8(例如GBK), str1基本上是个乱码, str1和str3也不再等价

至于str2, 它无论什么时候都会输出 ‘\xe4\xb8\xad’ (不含引号, 在单引号的字符串中, 只有单引号本身需要转义成\’, 其它情况的\都视为普通字符处理

只解释第一个与第二个的区别,也就是单引号与双引号的区别

双引号:引号内部会被转义
单引号:引号内部不会被转义

$a = 123;

echo "output:$a";//output:123
echo 'output:$a';//output:$a

//下面的示例仅限linux的php-cli
echo "new line\nsecond line";
/*
会换行,输出:
new line
second line
*/

echo 'no new line\n aaa';
/*
不会换行,输出:
no new line\n aaa
*/

\x后跟着十六进制数字的属于转义字符,转义字符只有在双引号"中才起作用。单引号中只有对单引号本身'和反斜杠\的转义有效,其他的都无效。

PHP本身不区分字符编码。也就是说,$str1是一个三字节的字符串,字符串的三个字节分别是(十六进制编码)E4 B8 AD。如果在UTF-8编码中,就是字。其他编码中就不一定了。

$str2则是一个12字节的字符串,就是你输入的那些字符。

$str3则是一个字符串,如果你把文件以UTF-8编码保存,那就和$str1是一样。如果你以GBK保存,那就是两个字节的D6 D0,如果你以BIG5保存,就是A4 A4


不管是UTF-8、GBK还是BIG5,甚至于很多其他的语言编码,都是遵循EUC的,也就是说对于ASCII字符,他们的编码都是一致的,所以无论用哪种编码保存,对PHP的代码工作都不会有影响。但是对于非ASCII字符就有很大的区别。

所以PHP中的非ASCII字符要正常显示,就要保证你的保存编码和输出编码是一致的。如果是输出的是HTML,是通过meta标签或者在HTTP Header中声明编码的。如果不一致,那就会出现乱码了。

(看完/读完)这篇文章有何感想! www.sbf888.com的分享…