8.tcp粘包处理2

在上一节中由于EOF切割需要遍历整个数据包的内容,查找EOF,因此会消耗大量CPU资源。假设每个数据包为2M,每秒10000个请求,这可能会产生20G条CPU字符匹配指令。
因此我们使用 固定包头+包体协议 来处理粘包

//客户端代码
$client = new swoole_client(SWOOLE_SOCK_TCP,SWOOLE_SOCK_SYNC);

$client->set([
    'open_length_check'     => 1,
    'package_max_length'    => 2*1024*1024,  //允许包的最大长度2MB
    'package_length_type'   => 'N',   //N:无符号、网络字节序、4字节 (常用)
    'package_length_offset' => 0,     //整个包头加包体计算长度
    'package_body_offset'   =>'4',     //包体从第4字节开始计算长度
    'socket_buffer_size' => 2* 1024 *1024, //配置客户端连接的缓存区长度
]);

$client->connect('127.0.0.1',9800);

//发送数据,需要做粘包处理
//为了处理粘包,我们和服务端约定一个分隔符(比如\r\n)
/*for($i=0;$i<10;$i++){
    $client->send("123456\r\n");
}*/

//发送2MB的数据
$body = json_encode(str_repeat('a',2*1024*1024));  
//$body = 'zhangsan';
//php的pack函数 把数据装入一个二进制字符串,N表示 unsigned long(总是32位, big endian 字节顺序),32位就是4字节,和服务器的约定一样
$data = pack('N',strlen($body)).$body;

$client->send($data);

//接收数据
var_dump($client->recv());

//关闭,关闭不能这么草率,需要做应答
//如果后台发送3次数据,客户端就得接收3次,所以需要做好应答,否则还没接受完数据,就关闭连接,后面的数据接收不到了,同时服务器会显示收到错误的数据
//参考连接:[https://wiki.swoole.com/wiki/page/313.html](https://wiki.swoole.com/wiki/page/313.html)

//$client->close();

#----------------------------------------

//服务端代码
$server = new Swoole\Server("0.0.0.0",9800);

//设置进程数,必须为正正数,会产生2+worker_num个数个进程
$server->set([
    'open_length_check'     => 1,
    'package_max_length'    => 2*1024*1024,  //允许包的最大长度2MB
    'package_length_type'   => 'N',   //N:无符号、网络字节序、4字节 (常用)
    'package_length_offset' => 0,     //整个包头加包体计算长度
    'package_body_offset'   =>'4',     //包体从第4字节开始计算长度
    'buffer_output_size'   => 3*1024*1024     //设置输出缓冲区的大小
]);


//事件监听
//1。监听连接
$server->on('connect',function($server, $fd){
    echo "已连接到服务器:{$fd}".PHP_EOL;
});

//2。接收到客户端消息
$server->on('receive',function($server, $fd, $from_id, $data){
    //var_dump('我是服务端接收到的数据长度为:'.strlen($data));

    //解包,并且截取数据包
    //$info = unpack('N',$data);
    //var_dump($info);
    //var_dump(substr($data,4));


    //给客户端返回消息,(客户端发送过来时也是)发送消息时需要确认数据到达,然后再次发送数据,否则发送多条数据,占满了缓冲区之后,后面的数据会溢出,从而被丢弃
    $server->send($fd,$data);
    $server->send($fd,$data);
    $server->send($fd,$data);

});


//3。连接关闭
$server->on('close',function(){
    echo "已关闭连接".PHP_EOL;
});

//开启服务
$server->start();

//WARNING   swProtocol_recv_check_length: package is too big, remote_addr=127.0.0.1:41693, length=825373496
//报错是因为我们没有按规定(包头+包体)格式发送数据包,或者是发送的数据大小超过了服务器的限制,这里我们限制了2MB


//  WARNING swFactoryProcess_finish (ERRNO 1202): The length of data [2097158] exceeds the output buffer size[2097152], please use the sendfile, chunked transfer mode or adjust the buffer_output_size
//报错是因为发送数据超过输出缓冲区的大小buffer_output_size
//单位为字节,默认为2M,如设置32 * 1024 *1024表示,单次Server->send最大允许发送32M字节的数据
//调用Server->send, Http\Server->end/write,WebSocket\Server->push 等发送数据指令时,单次最大发送的数据不得超过buffer_output_size配置。
//注意此函数不应当调整过大,避免拥塞的数据过多,导致吃光机器内存
//开启大量Worker进程时,将会占用worker_num * buffer_output_size字节的内存

说明:
ackage_length_type 长度值的类型
长度值的类型,接受一个字符参数,与php的pack函数一致。目前swoole支持10种类型:
c:有符号、1字节
C:无符号、1字节
s:有符号、主机字节序、2字节
S:无符号、主机字节序、2字节
n:无符号、网络字节序、2字节 (常用)
N:无符号、网络字节序、4字节 (常用)
l:有符号、主机字节序、4字节(小写L)
L:无符号、主机字节序、4字节(大写L)
v:无符号、小端字节序、2字节
V:无符号、小端字节序、4字节

对于任何的可靠的消息发送来讲,一定要有一个消息的确认机制、重试机制(IM(websockt))

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354