websocket 多聊天室功能

websocket 类也是在网上找到的。 修改后可以用来创建多房间聊天室。可以发送图片表情,图片,及文字。

分享的代码,已经测试。可正常运行

HTML 端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/>
    <title>直播课程</title>
    <link rel="stylesheet" href="css/base.css">
    <link rel="stylesheet" href="css/zhibo.css">
    <script type="text/javascript" src="js/jquery-1.11.3.min.js"></script>
</head>
<body class="scope">
    <div style="width: 100%; height:250px;">
        <script type="text/javascript" src="player/sewise.player.min.js"></script>
        <script type="text/javascript">
        var videourl='视屏播放地址不用写';
            SewisePlayer.setup({
                server: "vod",
                type: "m3u8",
                autostart: "true",
                videourl: videourl,
                    skin: "vodWhite",
                    title: "三年级预备课程一",
                    claritybutton: "disable",
                    lang: "zh_CN"
            });
        </script>
    </div>
    
    <div class="log  comment" id="log">
          <div class="luck">
                      <div class="user"><img src="img/user.png"></div>
                      <div class="content1"><span class="luckyP">奕佚奕佚</span><span class="yuanwang">我是用户1我是用是用户1我是用户1我是用户1我是用户1</span></div>
          </div>     
             <div class="luck">
                      <div class="user"><img src="img/user.png"></div>
                      <div class="content1"><span class="luckyP">莫寒</span><span class="yuanwang"><img class="chat_pic" src="img/pic.jpg" alt=""></span></div>
             </div>
             <div class="luck">
                      <div class="user"><img src="img/user.png"></div>
                      <div class="content1"><span class="luckyP">奕佚奕佚</span><span class="yuanwang">我是用户1我是用是用户1我是用户1我是用户1我是用户1</span></div>
          </div>
             <div class="luck">
                      <div class="user"><img src="img/user.png"></div>
                      <div class="content1"><span class="luckyP">奕佚奕佚</span><span class="yuanwang">我是用户1我是用是用户1我是用户1我是用户1我是用户1</span></div>
          </div>     
             <div class="luck">
                      <div class="user"><img src="img/user.png"></div>
                      <div class="content1"><span class="luckyP">莫寒</span><span class="yuanwang"><img class="chat_pic" src="img/150599173575244039.jpg" alt=""></span></div>
             </div>
              <div class="luck">
                      <div class="user"><img src="img/user.png"></div>
                      <div class="content1"><span class="luckyP">奕佚奕佚</span><span class="yuanwang">我是用户1我是用是用户1我是用户1我是用户1我是用户1</span></div>
          </div>     
    </div>
    <div class="sendCon">
        <p class="info">
            <span class="emoji"> <input type="button" value=":)"></span>
            <span class="placeholder"><img  src="img/pic.jpg" alt=""><input type="file" id="file_img" onchange="preImg(this.id,'yulan_img')"></span>
            <span class="text"><input type="text" id="text" placeholder=""></span>
            <span class="send"><input type="button" class="btn" value="发送" onclick="sendText()"></span>
        </p>
        <ul class="emojiCon"></ul>
    </div>

<script>
    var serverUrl="http://192.168.3.240";  //图片服务器的地址ip
    var url="ws://你自已访问的ip:端口(8000)";
    function link(){
        socket=new WebSocket(url);
        socket.onopen=function(){
            // alert('连接成功')
        };
        socket.onerror=function(errorEvent){
            // alert('error');
        }
        socket.onmessage=function(msg){
            setMsg(msg.data);
            console.log(msg);
        }
        // socket.onclose=function(){setMsg('断开连接')}
    }
    function closeScoket(){
        socket.close();
        socket=null;
    }
    //向页面中实时更新消息数据
    function setMsg(var1){
        var obj=JSON.parse(var1);
        if(obj.type==1){
            $('.log').append('<div class="luck">'
                      +'<div class="user"><img src="img/user.png"></div>'
                      +'<div class="content1"><span class="luckyP">奕佚奕佚</span>:<span class="yuanwang">'+obj.msg+'</span></div></div>' );
            add();
        }else{
            var img = new Image();
            img.src=obj.msg;
            img.onload=function(){
                var isPic='';
                //width>30 表示不是表情包图片
                if(img.width>30){
                    isPic='<img class="chat_pic" src="'+obj.msg+'" alt="">';
                }else{
                    isPic='<img class="chat_pic1" src="'+obj.msg+'" alt="">'
                }
                $('.log').append('<div class="luck">'
                              +'<div class="user"><img src="img/user.png"></div>'
                              +'<div class="content1"><span class="luckyP">奕佚奕佚</span>:<span class="yuanwang">'+isPic+'</span></div></div>' );
                
                add();
            }
        }
    }

    var arr=[1,2,3,4];
    //发送文字
    function sendText(id){
        var json;
        if($('#'+id).attr('src')==undefined){
            json=JSON.stringify({'room':arr[1],'type':'1','msg':$('#text').val()});
            if($('#text').val()==""){
                $('body').append(pop("消息不能为空"));
                return;
            }
        }else{
            json=JSON.stringify({'room':arr[1],'type':'2','msg':$('#'+id).attr('src')});
            $('.emojiCon').css('display','none');
        }
        socket.send(json);
        $('#text').val('');
    }
    //发送图片
    function sendPic(){
        $.ajax({
            url:''+serverUrl+'/test/Home/index/base64_decode',
            type:'post',
            data:{'msg':$('#yulan_img').attr('src')},
            dataType:'html',
            success:function(data){
                console.log(data);
                var json=JSON.stringify({'room':arr[3],'type':'2','msg':data});
                socket.send(json);
                $('.mask').remove();
            },
            error:function(event){
                $('body').append(pop('服务器开小差啦~'))
            }
        })
    }
    //让讨论区的滚动条始终在底部 让用户立马看到自己的消息
    function add(){
        var div = document.getElementById('log');
        div.scrollTop = div.scrollHeight;
    }
    //加载表情包
    function  afterLoad(){
        var html='';
        for(var i=0;i<91;i++){
            html+='<li><img id="emoji_'+(i+1)+'" οnclick="sendText(id)" src="'+serverUrl+'/test/Public/img/qq/'+(i+1)+'.gif" alt=""></li>';
        }
        $('.emojiCon').html(html);
    }
    //图片预览
    function preImg(sourceId, targetId) {  
            if (typeof FileReader === 'undefined') {  
                alert('Your browser does not support FileReader...');  
                return;  
            }  
            var reader = new FileReader();  
      
            reader.onload = function(e) {  
                var img = document.getElementById(targetId);  
                img.src = this.result;  
                var w=img.width;
                var h=img.height;
                var winW=$(window).width();
                var winH=$(window).height();
                var marginTop=parseInt((winH-40-h)/2);
                var marginLeft=parseInt((winW-w
                    )/2);

                if(w/h>1.2){
                    $(img).css('width',winW).css('margin-top',marginTop);
                    alert("marginTop:"+marginTop);
                }else if(h/w>2){//超长图的时候 滚动条显示
                    $('.over_pic').css('height',winH-40).css('overflow','scroll');
                    $(img).css('width',winW);
                }else{//竖图的时候 
                    $(img).css('height',winH-40).css('margin-left',marginLeft);
                    alert("marginLeft:"+marginLeft);
                }
            }  
            reader.readAsDataURL(document.getElementById(sourceId).files[0]);  
            
            $('body').append('<div class="mask scope"><div class="over_pic"><img id="yulan_img" src="" alt=""></div>'
                +'<p><button class="sure" οnclick="sendPic()">确认</button></p></div>');
    }  

    $(function(){
        link();
        afterLoad();
        add();
        $('.log').css('height',$(window).height()*0.65+'px');
        $('.emoji').click(function(){
            $('.emojiCon').show();
        })
    })
</script> 

</body>

</html>

 

CSS 前端代码  bass

@charset "utf-8";
/* 禁用iPhone中Safari的字号自动调整 */
html {  
    -webkit-text-size-adjust: 100%; 
    -ms-text-size-adjust: 100%;
    font-family:"微软雅黑",Arial,sans-serif;
}
/* 去除iPhone中默认的input样式 */
input{/* -webkit-appearance:none; */ resize: none;}
/* 取消链接高亮  */
body,div,ul,li,ol,h1,h2,h3,h4,h5,h6,input,textarea,select,p,dl,dt,dd,a,img,button,form,table,th,tr,td,tbody,article,
aside, details,figcaption,figure,footer,header,hgroup, menu,nav,section{
  -webkit-tap-highlight-color:rgba(0, 0, 0, 0);
}
/* 设置HTML5元素为块 */
article, aside, details,figcaption,figure,footer,header,hgroup, menu,nav,section {
    display: block;
}
/* 图片自适应 */
img {width: 100%;height: auto;width:auto\9; /* ie8 */
    -ms-interpolation-mode:bicubic;/*为了照顾ie图片缩放失真*/}
*:focus {outline:none;}
/* 清零 */
body,div,ul,li,ol,h1,h2,h3,h4,h5,h6,input,textarea,select,p,dl,dt,dd,
a,img,button,form,table,th,tr,td,tbody,article,
aside, details,figcaption,figure,footer,header,hgroup, menu,nav,section
    {
        margin:0; 
        padding:0; 
        border:none;
    }
em,i{font-style:normal;}
strong{font-weight: normal;}
.clearfix:after{content:""; display:block; visibility:hidden; height:0; clear:both;}
.clearfix{zoom:1;}
a{text-decoration:none; color:#969696;}
a:hover{ text-decoration:none;}
ul,ol,li{list-style:none;}
fieldset,img{border: none;}
q:before,q:after {content:"";}
input:password {ime-mode:disabled;}
*{box-sizing:border-box;}
.scope{min-width:320px; max-width:750px; margin: 0 auto;}
*{
    margin: 0;
    padding: 0;
}
@media screen  and (max-width: 750px){
    html{font-size:30px;}
}
@media screen and (min-width:640px) and (max-width:749px){
    html{font-size:25px; }
}
@media screen and (min-width:480px) and (max-width:639px){
    html{font-size:20px; }
}
@media screen and (min-width:320px) and (max-width:479px){
    html{font-size:15px; }
}

/*body{font-size:62.5%;}*/
fieldset,img{border:0}
a{text-decoration:none;color:#000;outline:none}
li{list-style:none}
h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}
input,button,textarea,select,optgroup,option{
    font-family:inherit;font-size:inherit;
    font-style:inherit;font-weight:inherit}
input,button,textarea,select{*font-size:100%}
.clear:after{
  display:block; 
  content:"clear"; 
  height:0; 
  clear:both;
  visibility:hidden;
}
.clear{zoom:1;}

CSS 前端代码  zhibo

.comment{
    overflow: scroll;
    border:1px solid red;
    padding:2%;
}
.luck{
    padding: 10px 0 0 0;
    overflow:hidden;
}
.luckyP{
    color:#44c6dd;
}
.chat_pic{
    width:40%;
    display:inline-block;
    vertical-align: top;
}
.chat_pic1{
    width:10%;
    vertical-align: middle;
}
.user img{
    width:40%;    
}
.user,.content1{
    float:left;
}
.user{
    width:15%;
    text-align: center;
    vertical-align: middle;
}
.content1{
    width:85%;
    line-height:25px;
}
.sendCon{
    position:fixed;
    bottom:0;
    left:0;
    right:0;
    padding:2%;
    background:#fff;
    border:1px solid #ddd;
    min-width:320px;
    max-width:750px;
    margin:0 auto;
}
.info span{
    display:inline-block;
}
.placeholder{
    width:15%;
    position:relative;
    text-align: center;
    vertical-align: middle;
}
    input[type="file"]{
        width:80%;
        position:absolute;
        left:2%;
        top:2%;
        opacity:0;
    }
    .placeholder img{
        width:65%;

    }
.emoji{
    width:10%;
    text-align: center;
    /*vertical-align: middle;*/
    /*border:1px solid red;*/
}
    .emoji input{
        width:100%;
        padding:8% 2%;
        border:1px solid #ddd;
        background:#fff;

    }
    /*.emoji img{
        width:80%;
        border:1px solid blue;
        vertical-align: middle;
    }*/
.text{
    width:55%;
}
    #text{
        width:100%;
        border:1px solid #ddd;
        padding:2%;
    }
.send{
    width:15%;
}
    .btn{
        width:100%;
        background:#86e2fd;
        color:#fff;
        padding:9% 2%;
        vertical-align: middle;
    }

.mask{
    background:rgba(0,0,0,0.9);
    width:100%;
    height:100%;
    position:fixed;
    left:0;
    top:0;
    /*display:none;*/
}
.sure{
    background:#19ad17;
    color:#fff;
    padding:10px;
}
.mask p{
    text-align: right; 
    position:absolute;
    bottom:0;
    left:0;
    right:0;
    height:40px;
    vertical-align: middle;
}
.over_pic img{
    display:block;
}
/*表情包div*/
.emojiCon{
    position:absolute;
    bottom:0;
    left:0;
    display:none;
    background:#fff;
}
.emojiCon li{
    border:1px solid #ddd;
    float:left;
    width:8.33%;
}

 

php  服务端代码 server.php

<?php
    
    include 'websocket.class.php';
    
    $config=array(
    
    'address'=>'你自已ip地址',  //注意事 项 linux下云服务器,用ifconfig 查看自已的内网ip  外网访问的ip 是用写在html那块的
    
    'port'=>'8000',
    
    'event'=>'WSevent',//回调函数的函数名
    
    'log'=>true,
    
    );
    
    $websocket = new websocket($config);
    
    $websocket->run();

function WSevent($type,$event){
  global $websocket;
    if('in'==$type){
      $websocket->log('客户进入id:'.$event['k']);
    }elseif('out'==$type){
      $websocket->log('客户退出id:'.$event['k']);
    }elseif('msg'==$type){
      $websocket->log($event['k'].'消息:'.$event['msg']);
      roboot($event['sign'],$event['msg']);
    }
}
function roboot($sign,$t){

global $websocket;

    $msg_arr = json_decode($t,true);
    foreach($websocket->users as $k =>&$v){
        if(empty($v['room'])){
            $v['room']=$msg_arr['room'];
        }
        if($v['room'] ==$msg_arr['room']){
             $websocket->idwrite($k,$t);
        }
    }
}
    

php 服务羰代码  websocket.class.php

<?php
/*
创建类websocket($config);
$config结构:
$config=array(
  'address'=>'192.168.0.200',//绑定地址
  'port'=>'8000',//绑定端口
  'event'=>'WSevent',//回调函数的函数名
  'log'=>true,//命令行显示记录
);

回调函数返回数据格式
function WSevent($type,$event)

$type字符串 事件类型有以下三种
in  客户端进入
out 客户端断开
msg 客户端消息到达
均为小写

$event 数组
$event['k']内置用户列表的userid;
$event['sign']客户标示
$event['msg']收到的消息 $type='msg'时才有该信息

方法:
run()运行
search(标示)遍历取得该标示的id
close(标示)断开连接
write(标示,信息)推送信息
idwrite(id,信息)推送信息

属性:
$users 客户列表
结构:
$users=array(
[用户id]=>array('socket'=>[标示],'hand'=[是否握手-布尔值]),
[用户id]=>arr.....
)
*/

class websocket{
    public $log;
    public $event;
    public $signets;
    public $users;  
    public $master; 
    public function __construct($config){
        if (substr(php_sapi_name(), 0, 3) !== 'cli') {
            die("请通过命令行模式运行!");
        }
        error_reporting(E_ALL);
        set_time_limit(0);
        ob_implicit_flush();
        $this->event = $config['event'];
        $this->log = $config['log'];
        $this->master=$this->WebSocket($config['address'], $config['port']);
        $this->sockets=array('s'=>$this->master);
    }
    function WebSocket($address,$port){
         $server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1);
        socket_bind($server, $address, $port);
        socket_listen($server);
        $this->log('开始监听: '.$address.' : '.$port);
        return $server;
    }
  function run(){
    while(true){
      $changes=$this->sockets;
      @socket_select($changes,$write=NULL,$except=NULL,NULL);
      foreach($changes as $sign){
        if($sign==$this->master){
          $client=socket_accept($this->master);
          $this->sockets[]=$client;
          $user = array(
            'socket'=>$client,
            'hand'=>false,
          );
          $this->users[] = $user;
          $k=$this->search($client);
          $eventreturn = array('k'=>$k,'sign'=>$sign);
          $this->eventoutput('in',$eventreturn);
        }else{
          $len=socket_recv($sign,$buffer,2048,0);
          $k=$this->search($sign);
          $user=$this->users[$k];
          if($len<7){
            $this->close($sign);
            $eventreturn = array('k'=>$k,'sign'=>$sign);
            $this->eventoutput('out',$eventreturn);
            continue;
          }
          if(!$this->users[$k]['hand']){//没有握手进行握手
            $this->handshake($k,$buffer);
          }else{
            $buffer = $this->uncode($buffer);
            $eventreturn = array('k'=>$k,'sign'=>$sign,'msg'=>$buffer);
            $this->eventoutput('msg',$eventreturn);
          }
        }
      }
    }
  }
  function search($sign){//通过标示遍历获取id
    foreach ($this->users as $k=>$v){
      if($sign==$v['socket'])
      return $k;
    }
    return false;
  }
  function close($sign){//通过标示断开连接
    $k=array_search($sign, $this->sockets);
    socket_close($sign);
    unset($this->sockets[$k]);
    unset($this->users[$k]);
  }
  function handshake($k,$buffer){
    $buf  = substr($buffer,strpos($buffer,'Sec-WebSocket-Key:')+18);
    $key  = trim(substr($buf,0,strpos($buf,"\r\n")));
    $new_key = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
    $new_message = "HTTP/1.1 101 Switching Protocols\r\n";
    $new_message .= "Upgrade: websocket\r\n";
    $new_message .= "Sec-WebSocket-Version: 13\r\n";
    $new_message .= "Connection: Upgrade\r\n";
    $new_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n";
    socket_write($this->users[$k]['socket'],$new_message,strlen($new_message));
    $this->users[$k]['hand']=true;
    return true;
  }
  function uncode($str){
    $mask = array();  
    $data = '';  
    $msg = unpack('H*',$str);  
    $head = substr($msg[1],0,2);  
    if (hexdec($head{1}) === 8) {  
      $data = false;  
    }else if (hexdec($head{1}) === 1){  
      $mask[] = hexdec(substr($msg[1],4,2));
      $mask[] = hexdec(substr($msg[1],6,2));
      $mask[] = hexdec(substr($msg[1],8,2));
      $mask[] = hexdec(substr($msg[1],10,2));
      $s = 12;  
      $e = strlen($msg[1])-2;  
      $n = 0;  
      for ($i=$s; $i<= $e; $i+= 2) {  
        $data .= chr($mask[$n%4]^hexdec(substr($msg[1],$i,2)));  
        $n++;  
      }  
    }  
    return $data;
  }
    function code($msg){
      $msg = preg_replace(array('/\r$/','/\n$/','/\r\n$/',), '', $msg);
      $frame = array();  
      $frame[0] = '81';  
      $len = strlen($msg);  
      $frame[1] = $len<16?'0'.dechex($len):dechex($len);
      $frame[2] = $this->ord_hex($msg);
      $data = implode('',$frame);
      return pack("H*", $data);
    }
    function ord_hex($data)  {  
      $msg = '';  
      $l = strlen($data);  
      for ($i= 0; $i<$l; $i++) {  
        $msg .= dechex(ord($data{$i}));  
      }  
      return $msg;  
    }

    function idwrite($id,$t){//通过id推送信息
      if(!$this->users[$id]['socket']){return false;}//没有这个标示
      $t=$this->code($t);
      return socket_write($this->users[$id]['socket'],$t,strlen($t));
    }
    function write($k,$t){//通过标示推送信息
      $t=$this->code($t);
      return socket_write($k,$t,strlen($t));
    }
    function eventoutput($type,$event){//事件回调
      call_user_func($this->event,$type,$event);
    }
    function log($t){//控制台输出
      if($this->log){
        $t=$t."\r\n";
        fwrite(STDOUT, iconv('utf-8','gbk//IGNORE',$t));
      }
    }
}

 

php 上传图片异步处理代码 

$update_path = "Upload/";  
        $msg = $_POST['msg'];
        $exe = str_replace('/', '.', strstr(strstr($msg, ';', TRUE), '/'));
        $exe = $exe == '.jpeg' ? '.jpg' : $exe;
        $tmp = base64_decode(substr(strstr($msg, ','), 1));
        $path = $update_path . md5(time()) . $exe;
        $res  =file_put_contents($path, $tmp);
        echo "http://".$_SERVER['SERVER_NAME']."/test/".$path;

 

window 下  打开dos 命令  找到php.exe 文件位置。用php.exe 执行 server.php 文件开启服务器监听。   php.exe   server.php

打开html页面,点击链接,就可以链接websocket了。提示成功,便可以发送信息了。

 

注意事项目:linux 下 滥听端口时,注意服务器防火墙是否开启端口过滤。 Linux  有iptables firewall 两个防火墙软件件

 

转载于:https://www.cnblogs.com/zx1989031/p/6119165.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值