CoCos Creator、WebSocket聊天室

文章目录

  • 前言
  • 一、服务端 Spring Boot、Netty
  • 二、客户端 CoCos Creator 2.4.6、WebSocket
    • 1.界面
    • 2.代码
  • 运行
      • 运行服务器
      • 运行 cocos
  • 写在最后


前言

今天学习了CoCos Creator、WebSocket聊天室
参考文章:https://blog.csdn.net/u012987441/article/details/106863545/


一、服务端 Spring Boot、Netty

别人用的node.js做服务器,这里我用了基于java的netty做服务器
若你非后端人员,无spring boot及netty基础,可以用我写好的服务器文件,服务端部分可以略过。

链接:https://pan.baidu.com/s/1beO61aCmhBx6wltnveQFKA 
提取码:jyad

创建一个Spring Boot项目
引入依赖:

		
        
            io.netty
            netty-all
            4.1.66.Final
        
        
        
            org.projectlombok
            lombok
            1.18.20
        

项目结构:
CoCos Creator、WebSocket聊天室_第1张图片
WebSocketServer

package com.cocos.netty.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class WebSocketServer {
    private int port;

    public WebSocketServer(int port){
        this.port = port;
    }

    public void run(){
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(boss,worker)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,128)       //最大客户端连接数128
                    .childOption(ChannelOption.SO_KEEPALIVE,true)   //客户端保持活动连接
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new WebSocketServerInitializer());
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}

WebSocketServerInitializer

package com.cocos.netty.server;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

public class WebSocketServerInitializer extends ChannelInitializer {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        //http的解编码器
        ch.pipeline().addLast("Codec",new HttpServerCodec());
        //该处理器是处理大数据传输的,用以维护管理大文件传输过程中时复杂的状态
        ch.pipeline().addLast("ChunkedWrite",new ChunkedWriteHandler());
        //将HTTP消息的多个部分合成一条完整的HTTP消息,接收累计器,将多个段聚合,保证http请求完整性,用于处理大量数据
        ch.pipeline().addLast("Aggregator",new HttpObjectAggregator(64 * 1024));
        ch.pipeline().addLast("Protocol",new WebSocketServerProtocolHandler("/ws"));
        ch.pipeline().addLast("MyHandler",new WebSocketServerHandler());
    }
}

WebSocketServerHandler

package com.cocos.netty.server;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import java.text.SimpleDateFormat;
import java.util.Date;

public class WebSocketServerHandler extends SimpleChannelInboundHandler {
    //定义一个channel组,管理所有channel  (GlobalEventExecutor.INSTANCE 是一个全局的事件执行器,是一个单例)
    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    //处理时间
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        channelGroup.forEach(channel -> {
            if(ctx.channel() != channel){
                channel.writeAndFlush(new TextWebSocketFrame("[客户端]" + sdf.format(new Date()) + " " + ctx.channel().id().asShortText() + ":" + msg.text()));
            }else {
                channel.writeAndFlush(new TextWebSocketFrame("[我]" + sdf.format(new Date()) + " " + ctx.channel().id().asShortText() + ":" + msg.text()));
            }
        });
        System.out.println(ctx.channel().id().asShortText() + ":" + msg.text());
    }

    //新的客户端连接
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        //id 表示唯一的值,(有LongText()和ShortText()两种),LongText 是唯一的值;ShortText()不是唯一的
        channelGroup.writeAndFlush(sdf.format(new Date()) + " " + ctx.channel().id().asShortText() + " 加入了!");
        channelGroup.add(ctx.channel());
        super.handlerAdded(ctx);
    }

    //客户端活动
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(sdf.format(new Date()) + " " + ctx.channel().id().asShortText() + " 已上线!");
        super.channelActive(ctx);
    }

    //客户端不活动
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(sdf.format(new Date()) + " " + ctx.channel().id().asShortText() + " 断线了!");
        channelGroup.remove(ctx.channel());
        super.channelInactive(ctx);
    }

    //断开连接
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        channelGroup.writeAndFlush(sdf.format(new Date()) + " " + ctx.channel().id().asShortText() + " 离开了!");
        System.out.println(ctx.channel().id().asShortText()+ " 离开了!");
        super.handlerRemoved(ctx);
    }

    //客户端异常
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("发生异常了 " + cause.getMessage());
        ctx.close();
        super.exceptionCaught(ctx, cause);
    }
}

NettyCocosApplication

package com.cocos.netty;

import com.cocos.netty.server.WebSocketServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class NettyCocosApplication {

    public static void main(String[] args) {
        SpringApplication.run(NettyCocosApplication.class, args);
        WebSocketServer webSocketServer = new WebSocketServer(8080);
        webSocketServer.run();
    }

}

测试,网页hello.html




    
    Title




    

启动Netty项目,打开网页
CoCos Creator、WebSocket聊天室_第2张图片
此处进行发送测试
CoCos Creator、WebSocket聊天室_第3张图片
将项目打包,pom添加:


        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

CoCos Creator、WebSocket聊天室_第4张图片

二、客户端 CoCos Creator 2.4.6、WebSocket

版本:2.4.6,TypeScript

1.界面

CoCos Creator、WebSocket聊天室_第5张图片
细节处:
scrollViwe组件删掉bar和item
添加Widget组件
CoCos Creator、WebSocket聊天室_第6张图片
CoCos Creator、WebSocket聊天室_第7张图片

2.代码

NetMoudle.ts

const {ccclass, property} = cc._decorator;

@ccclass
export default class GameNet extends cc.Component {
    private static Instance: GameNet = null;
    private ws: WebSocket = null;

    private constructor(){
        super();
    }

    public static getInstance(): GameNet {
        if (GameNet.Instance === null) {
            GameNet.Instance = new GameNet();
        }
        return GameNet.Instance;
    }

    /**
     * 初始化并连接WebSocket服务端
     * @param callback 回调函数
     * @param target 绑定this
     * @returns 
     */
    public init(callback: Function, target: any): void {
        if (this.ws !== null) return;
        this.ws = new WebSocket('ws://localhost:8080/ws');
        this.ws.onopen = (event: MessageEvent)=>{
            callback.call(target, "登录成功");
        }

        this.ws.onmessage = (event: MessageEvent)=>{
            callback.call(target, event.data);
        }

        this.ws.onerror = (event: MessageEvent)=>{
            console.log("WebSocket error:" + event);
            this.ws.close();
        }

        this.ws.onclose = ()=>{
            if (this.ws.readyState === WebSocket.CLOSED) {
                console.log("WebSocket already close");
            }
            console.log("WebSocket close");
        }
    }

    public send(data: any): void {
        if (this.ws !== null && this.ws.readyState !== WebSocket.OPEN) return;
        this.ws.send(data);
    }
}

GameManager.ts

const {ccclass, property} = cc._decorator;

import GameNet from "./NetModule";

@ccclass
export default class GameManager extends cc.Component {

    @property(cc.ScrollView)
    scrollView: cc.ScrollView = null;
    @property(cc.EditBox)
    editBox: cc.EditBox = null;
    @property(cc.Button)
    login_btn: cc.Button = null;
    @property(cc.Button)
    send_btn: cc.Button = null;
    
    posY: number = 0;

    start () {
        this.login_btn.node.on(cc.Node.EventType.TOUCH_END, this.login, this);
        this.send_btn.node.on(cc.Node.EventType.TOUCH_END, this.sendMsg, this);
    }

    private login(){
        GameNet.getInstance().init(this.getMsg, this);
    }

    private sendMsg(){
        let data: string = this.editBox.string;
        if (data === null) return;
        GameNet.getInstance().send(data.toString());
    }

    private getMsg(data: any){
        let label: cc.Label = (new cc.Node).addComponent(cc.Label);
        label.string = data;
        label.fontSize = 20;
        label.node.anchorX = 0;
        label.node.anchorY = 1;
        label.node.x = -this.scrollView.content.width * 0.5 + 10;
        label.node.y = this.posY;
        this.scrollView.content.addChild(label.node);
    
        this.posY -= label.node.height;
        if (Math.abs(this.posY) > this.scrollView.content.height) {
            this.scrollView.content.height = Math.abs(this.posY);
            this.scrollView.scrollToBottom();
        }
        this.editBox.string = '';
    }
}

运行

运行服务器

本地文件找到spring boot 项目的target文件夹,
按住shift并右击打开dos命令窗口,运行写好的项目
若要上传到服务器,可以更改spring boot 项目、ts代码的ip地址为服务器ip

java -jar 文件名.jar

java -jar netty-cocos-0.0.1-SNAPSHOT.jar

运行 cocos

多开两个窗口
CoCos Creator、WebSocket聊天室_第8张图片
CoCos Creator、WebSocket聊天室_第9张图片
CoCos Creator、WebSocket聊天室_第10张图片

写在最后

个人学习记录,参考链接已放上。

你可能感兴趣的:(笔记,websocket,netty,cocos)