博客列表 >商桥系统的基本通讯原理

商桥系统的基本通讯原理

我是郭富城
我是郭富城原创
2020年07月04日 00:05:181152浏览

1. 客户端代码

1.1 控制器

  1. <?php
  2. namespace App\Http\Controllers;
  3. use Illuminate\Http\Request;
  4. // 仿百度商桥客户端
  5. class Bchat extends Controller
  6. {
  7. //百度商桥首页
  8. public function index() {
  9. return view('bchat/index');
  10. }
  11. }

1.2 客户端视图

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>仿百度商桥</title>
  6. <link rel="stylesheet" href="/static/plugins/layui/css/layui.css">
  7. <script src="/static/plugins/layui/layui.js"></script>
  8. </head>
  9. <body>
  10. <div>
  11. 这是测试内容啊老弟
  12. </div>
  13. </body>
  14. </html>
  15. <script>
  16. layui.use(['layer'], function() {
  17. var layer = layui.layer;
  18. $=layui.jquery;
  19. init_bchat();
  20. });
  21. // 百度商桥
  22. function init_bchat() {
  23. layer.open({
  24. type: 2,
  25. title: '百度商桥欢迎你',
  26. // shadeClose: true,
  27. shade: 0.2,
  28. area: ['80%', '80%'],
  29. content: '/bchat/index', //iframe的url
  30. btn: ['发送'],
  31. yes: function(index, layero) {
  32. var body = layer.getChildFrame('body', index);
  33. var iframeWin = window[layero.find('iframe')[0]['name']]; //得到iframe页的窗口对象,执行iframe页的方法:
  34. iframeWin.send();
  35. }
  36. });
  37. }
  38. </script>
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>客户端的聊天窗口</title>
  6. <link rel="stylesheet" href="/static/plugins/layui/css/layui.css">
  7. <script src="/static/plugins/layui/layui.js"></script>
  8. <link rel="stylesheet" href="/static/css/bchat.css">
  9. </head>
  10. <body>
  11. <!-- 消息内容展示 -->
  12. <div class="msg_show">
  13. </div>
  14. <hr class="layui-bg-black">
  15. <!-- 消息发送区 -->
  16. <div class="msg_send" contenteditable="true">请输入要发送的内容</div>
  17. </body>
  18. </html>
  19. <script>
  20. layui.use(['layer'], function() {
  21. var layer = layui.layer;
  22. $=layui.jquery;
  23. });
  24. // 假设服务端ip为127.0.0.1
  25. ws = new WebSocket("ws://127.0.0.1:2000");
  26. ws.onopen = function() {
  27. var data={};
  28. data.type= 'login';
  29. data.group = 'member';
  30. ws.send(JSON.stringify(data));
  31. // alert("连接成功");
  32. // ws.send('tom');
  33. // alert("给服务端发送一个字符串:tom");
  34. };
  35. ws.onmessage = function(e) {
  36. var data=JSON.parse(e.data);
  37. if (data.kefu_id > 0) {
  38. var html='<div class="msg_item">\
  39. <div class="nickname">客服'+ data.kefu_id +'说:</div>\
  40. <div class="contents">'+ data.msg +'</div>\
  41. </div>';
  42. $('.msg_show').append(html);
  43. } else {
  44. var html='<div class="msg_item msg_customer">\
  45. <div class="nickname">我说:</div>\
  46. <div class="contents">'+ data.msg +'</div>\
  47. </div>';
  48. $('.msg_show').append(html);
  49. }
  50. };
  51. // <!-- 发送消息 -->
  52. function send() {
  53. var data={};
  54. data.group = 'member';
  55. data.type='msg';//发送类型是message
  56. // data.touid=1;//发给哪个客服
  57. data.msg=$('.msg_send').html();
  58. ws.send(JSON.stringify(data));
  59. $('.msg_send').html('');
  60. }
  61. </script>

1.3 效果图

2. 客服端代码

2.1 客服端控制器

  1. <?php
  2. namespace App\Http\Controllers\admins;
  3. use App\Http\Controllers\Controller;
  4. use Illuminate\Http\Request;
  5. //后台客服
  6. class Kefu extends Controller
  7. {
  8. //
  9. public function index() {
  10. return view('admins/kefu/index');
  11. }
  12. }

2.2 客服端视图

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>后台客服</title>
  6. <link rel="stylesheet" href="/static/plugins/layui/css/layui.css">
  7. <script src="/static/plugins/layui/layui.js"></script>
  8. <link rel="stylesheet" href="/static/css/bchat.css">
  9. </head>
  10. <body>
  11. <div class="kefu">
  12. <div class="kefu_title">客户接待中心</div>
  13. <div class="kefu_detail">
  14. <!-- 左侧客户列表区 -->
  15. <div class="member_list">
  16. </div>
  17. <!-- 右侧客户对话区 -->
  18. <div class="message_list">
  19. <!-- 当前的聊天内容 -->
  20. <div class="message_content">
  21. </div>
  22. <!-- 消息发送区域 -->
  23. <div class="message_send" contenteditable="true">
  24. </div>
  25. <div class="btn_send"><button class="layui-btn" onclick="sendmsg()">发送</button></div>
  26. </div>
  27. </div>
  28. </div>
  29. </body>
  30. </html>
  31. <script>
  32. var user_list=[];//新用户列表
  33. layui.use(['layer'], function() {
  34. var layer = layui.layer;
  35. $=layui.jquery;
  36. });
  37. // 假设服务端ip为127.0.0.1
  38. ws = new WebSocket("ws://127.0.0.1:2000");
  39. ws.onopen = function() {
  40. var data={};
  41. data.type= 'login';
  42. data.group = 'admin';
  43. ws.send(JSON.stringify(data));
  44. // alert("连接成功");
  45. // ws.send('tom');
  46. // alert("给服务端发送一个字符串:tom");
  47. };
  48. ws.onmessage = function(e) {
  49. // console.log(e.data);
  50. var data = JSON.parse(e.data);
  51. //新客户来了
  52. if (data.type==='login') {
  53. if ($.inArray(data.customer_id,user_list)===-1) {
  54. user_list.push(data.customer_id);
  55. }
  56. build_kefu_user_list();
  57. return;
  58. }
  59. // 客户连接断开
  60. if (data.type==='logout') {
  61. var index = $.inArray(data.connection_id,user_list);
  62. if (index > -1) {
  63. user_list.splice(index,1);
  64. }
  65. build_kefu_user_list();
  66. return;
  67. }
  68. var msg_member_list = $('#member_'+ data.customer_id);
  69. if (msg_member_list.length===0) {
  70. var html_container = '<div id="member_' + data.customer_id +'"></div>';
  71. $('.message_content').append(html_container);
  72. }
  73. var html='<div class="msg_item">\
  74. <div class="nickname">'+ data.customer_id +'说:</div>\
  75. <div class="contents">'+ data.msg +'</div>\
  76. </div>';
  77. $('#member_'+ data.customer_id).append(html);
  78. $('#member_'+ data.customer_id).show().siblings('div').hide();
  79. };
  80. //构建客服端的客户列表
  81. function build_kefu_user_list() {
  82. var html='';
  83. $.each(user_list,function(i,v){
  84. html+=('<div class="member_item" onclick="checkme(this)" member_id="'+v+'">客户:'+ v +'</div>');
  85. });
  86. $('.member_list').html(html);
  87. }
  88. // 和某个客户聊天
  89. function checkme(obj) {
  90. $(obj).addClass('active').siblings('div').removeClass('active');
  91. var member_id=$(obj).attr('member_id');
  92. $('#member_'+ member_id).show().siblings('div').hide();
  93. }
  94. // <!-- 发送消息 -->
  95. function sendmsg() {
  96. // 获取当前聊天的客户
  97. var touid =parseInt($('.member_list div[class*="active"]').attr('member_id'));
  98. if (isNaN(touid)) {
  99. return layer.alert('请先选择客户',{icon:2});
  100. }
  101. var data={};
  102. data.group = 'admin';
  103. data.type='msg';//发送类型是message
  104. data.touid=touid;//发给哪个客户
  105. data.msg=$('.message_send').html();
  106. ws.send(JSON.stringify(data));
  107. $('.message_send').html('');
  108. var html='<div class="msg_item msg_kefu">\
  109. <div class="nickname">我说:</div>\
  110. <div class="contents">'+ data.msg +'</div>\
  111. </div>';
  112. $('.message_content').append(html);
  113. }
  114. </script>

2.3 效果图

3. websocket

参考WebSocket即时通讯原理实战https://www.php.cn/blog/detail/22780.html
下载PHP socket即时通讯框架。
https://www.workerman.net/download/workermanzip

  1. <?php
  2. use Workerman\Worker;
  3. require_once __DIR__ . '/workerman/Autoloader.php';
  4. // 注意:这里与上个例子不同,使用的是websocket协议
  5. $ws_worker = new Worker("websocket://0.0.0.0:2000");
  6. // 启动4个进程对外提供服务
  7. $ws_worker->count = 4;
  8. // 当收到客户端发来的数据后返回hello $data给客户端
  9. $ws_worker->onMessage = function($connection, $data)
  10. {
  11. // 向客户端发送hello $data
  12. // $connection->send($data);
  13. // 给所有人发消息
  14. // global $ws_worker;
  15. // foreach($ws_worker->connections as $conn)
  16. // {
  17. // // $conn->send("user[{$connection->uid}] said: $data");
  18. // $conn->send($data);
  19. // }
  20. // 服务器端收到客户端的信息后返回数据给客户端
  21. var_dump($connection->id);
  22. // return;
  23. global $ws_worker;
  24. $data = json_decode($data,true);
  25. // print_r($data);
  26. // 客户端有人登录进来了
  27. if ($data['type']==='login'){
  28. // 赋值
  29. $connection->group = $data['group'];
  30. //客户登录的时候
  31. if ($data['group']==='member') {
  32. //随机分配一个客服姐姐给他
  33. $admin_list=[];
  34. foreach($ws_worker->connections as $conn) {
  35. if ($conn->group==='admin') {
  36. $admin_list[]=$conn->id;
  37. }
  38. }
  39. // 分配一个随机客服
  40. $myadmin_index = array_rand($admin_list,1);//键名
  41. $connection->touid=$admin_list[$myadmin_index];
  42. // 通知客服有新用户进来
  43. foreach($ws_worker->connections as $conn)
  44. {
  45. if ($conn->id === $connection->touid) {
  46. $data['customer_id'] = $connection->id;
  47. $conn->send(json_encode($data));
  48. }
  49. }
  50. }
  51. }
  52. // 有新的消息过来了
  53. if ($data['type']==='msg'){
  54. // 赋值
  55. // 客服(管理)登录进来,发消息给用户
  56. if ($connection->group === 'admin'){
  57. $touid = $data['touid'];
  58. $msg = $data['msg'];
  59. foreach($ws_worker->connections as $conn)
  60. {
  61. //向对应的用户发送消息
  62. if($touid === $conn->id) {
  63. $msgData = [];
  64. $msgData['type'] = 'msg';
  65. $msgData['kefu_id'] = $connection->id;
  66. $msgData['msg'] = $msg;
  67. $conn->send(json_encode($msgData));
  68. // 把数据储存到数据库
  69. $data = ['from_id'=>$connection->id,'to_uid'=>$touid,'msg'=>$msg];
  70. $url = 'http://laravel.edu/kefumsg/save_msg';
  71. curl_post($url,$data);
  72. // var_dump($res);
  73. }
  74. // $conn->send("user[{$connection->uid}] said: $data");
  75. }
  76. }
  77. // 客户端登录进来
  78. if ($connection->group === 'member'){
  79. // $touid=$data['touid'];
  80. foreach($ws_worker->connections as $conn)
  81. {
  82. //向对应的用户发送消息
  83. if($connection->touid === $conn->id) {
  84. $data['customer_id'] = $connection->id;
  85. $conn->send(json_encode($data));
  86. // 储存数据
  87. $data = ['from_id'=>$connection->id,'to_uid'=>$connection->touid,'msg'=>$data['msg']];
  88. $url = 'http://laravel.edu/kefumsg/save_msg';
  89. curl_post($url,$data);
  90. }
  91. // $conn->send("user[{$connection->uid}] said: $data");
  92. }
  93. }
  94. }
  95. // 用户链接断开的时候
  96. $ws_worker->onClose = function($connection)
  97. {
  98. // 通知客服,有人掉线了
  99. global $ws_worker;
  100. foreach($ws_worker->connections as $conn) {
  101. if ($conn->group==='admin') {
  102. $data=[];
  103. $data['type']='logout';
  104. $data['connection_id']=$connection->id;
  105. $conn->send(json_encode($data));
  106. }
  107. }
  108. };
  109. };
  110. // 定义一个http请求函数
  111. // $url 是请求的链接
  112. // $postdata 是传输的数据,数组格式
  113. function curl_post( $url, $postdata ) {
  114. $header = array(
  115. 'Accept: application/json',
  116. );
  117. //初始化
  118. $curl = curl_init();
  119. //设置抓取的url
  120. curl_setopt($curl, CURLOPT_URL, $url);
  121. //设置头文件的信息作为数据流输出
  122. curl_setopt($curl, CURLOPT_HEADER, 0);
  123. //设置获取的信息以文件流的形式返回,而不是直接输出。
  124. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  125. // 超时设置
  126. curl_setopt($curl, CURLOPT_TIMEOUT, 10);
  127. // 超时设置,以毫秒为单位
  128. // curl_setopt($curl, CURLOPT_TIMEOUT_MS, 500);
  129. // 设置请求头
  130. curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
  131. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE );
  132. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE );
  133. //设置post方式提交
  134. curl_setopt($curl, CURLOPT_POST, 1);
  135. curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata);
  136. //执行命令
  137. $data = curl_exec($curl);
  138. // 显示错误信息
  139. if (curl_error($curl)) {
  140. print "Error: " . curl_error($curl);
  141. } else {
  142. // 打印返回的内容
  143. curl_close($curl);
  144. return $data;
  145. }
  146. }
  147. // 运行worker
  148. Worker::runAll();

4. 效果演示

5. 总结

随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了。近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据。

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议