u3d简单网游的通信,拿某简单例子学习一下

这个例子是某网站的一个视频教程的例子,但教程没有提供代码,跟随教程敲代码根本做不出东西,所以第一课的时候有1700多人参加学习,完整听完的人数只有不到40,很多人都是第4课就放弃了,因为老师没有提供相关的工具代码,字符串解析根本无法通信,造成了听课人员的流失,其实听过这个课程之后,我觉得课程还是不错的,虽然没有提供工程样例和公共部分的代码,但如果有c#网络经验的话,完成这个例子其实也是可以的,因为,毕竟服务器端的代码是提供了,我觉得,弄到一起完全可以当成3d网游的一般框架来学习,看下我自己做的客户端的运行效果,界面的问题就不要吐槽了,因为没有什么都没提供,所以只好在自己电脑里面东拼西凑需要的东西,有些界面不太好看是很正常的,我们只是看这个的原理,

基本代码,net连接

using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System.IO;
using System;
using System.Text;
using LitJson;
using System.Threading;
using System.Collections.Generic;

public  class NetWorkScript 
{
    
    private static NetWorkScript script;
    private Socket socket;
    public static string host ="127.0.0.1";//服务器IP地址
    private int port = 10100;//服务器端口
    private byte[] readM = new byte[1024];
	private ByteArray ioBuff=new ByteArray();
	private int dataSize;
    private List<SocketModel> messages = new List<SocketModel>();
    private bool isRead = false;

    //获取连接对象
    public static NetWorkScript getInstance() {
        if (script == null) {
            //第一次调用的时候 创建单例对象 并进行初始化操作
            script = new NetWorkScript();
            script.init();
        }
       
        return script;
    }
    private void init() {
        try
        {
            //创建socket连接对象
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //连接到服务器
            socket.Connect(host, port);
            //连接后开始从服务器读取网络消息
            socket.BeginReceive(readM, 0, 1024, SocketFlags.None, ReceiveCallBack,readM);
            Debug.Log("socket session open");
        }
        catch (Exception e) {
            //连接失败 打印异常
            Debug.Log("Connect error:"+e.Message);
        }
    }

    public void sendMessage(int type, int area, int command, string message) {
        ByteArray arr= new ByteArray();
        arr.WriteInt(type);
        arr.WriteInt(area);
        arr.WriteInt(command);
        if (message != null)
        {
            arr.WriteInt(message.Length);
            arr.WriteUTFBytes(message);
            //  arr.WriteUTFBytes(message);
        }
        else {
            arr.WriteInt(0);
        }
        try
        {
            socket.Send(arr.Buffer);
        }
        catch {
           Debug.Log("socket error");
        }
    }

    public void onData()
    {
        //消息读取完成后开始解析 
		if(ioBuff.Length<4){
			//包头为长度4的整型
            isRead = false;
			return;
		}
		dataSize=ioBuff.ReadInt();
		Debug.Log("dataSize"+dataSize);
		if(dataSize>ioBuff.Length-4){
			//包长不够 等下个包的到来
			Debug.Log("包长不够");
			ioBuff.Postion=0;
            isRead = false;
			return;
		}
		ByteArray ioData=new ByteArray();
		ioData.WriteBytes(ioBuff.Buffer,4,dataSize);
		ioBuff.Postion+=dataSize;

                
                int type = ioData.ReadInt();//表示消息类型  我们这里有两种
                int area = ioData.ReadInt();//这里表示消息的区域码 在登录这样的服务器单例模块中 没有效果 在地图消息的时候用于区分属于哪张地图来的消息
                int command = ioData.ReadInt();//模块内部协议---具体稍后描述
                int len = ioData.ReadInt();

                string m=null;
                if (len > 0) { m = ioData.ReadUTFBytes((uint)len); }//这里开始就是读取服务器传过来的消息对象了 是一串json字符串
             //转换为Socket消息模型
                SocketModel model= new SocketModel();
                model.type = type;
                model.area = area;
                model.command = command;
                model.message = m;
                Debug.Log(type+"   "+area+"  "+command+"length"+(16+len));

                //消息接收完毕后,存入收到消息队列
                messages.Add(model);
		ByteArray bytes=new ByteArray();
        bytes.WriteBytes(ioBuff.Buffer, ioBuff.Postion, ioBuff.Buffer.Length - ioBuff.Postion);
		ioBuff=bytes;
		onData();
				//Debug.Log("插入队列后"+arr.Buffer[12+len+1]);
        
    }
    //这是读取服务器消息的回调--当有消息过来的时候BgenReceive方法会回调此函数
    private void ReceiveCallBack(IAsyncResult ar)
    {
        
        int readCount = 0;
        try
        {
            //读取消息长度
            readCount = socket.EndReceive(ar);//调用这个函数来结束本次接收并返回接收到的数据长度。 
            Debug.Log("读取消息长度" + readCount);
            byte[] bytes = new byte[readCount];//创建长度对等的bytearray用于接收
            Buffer.BlockCopy(readM, 0, bytes, 0, readCount);//拷贝读取的消息到 消息接收数组
            ioBuff.WriteBytes(bytes);
			Debug.Log(ioBuff.Buffer.Length);
            if (!isRead){
                isRead = true;
			    onData();//消息读取完成
            }
        }
        catch (SocketException)//出现Socket异常就关闭连接 
        {
           socket.Close();//这个函数用来关闭客户端连接 
            return;
        }
        socket.BeginReceive(readM, 0, 1024, SocketFlags.None, ReceiveCallBack,readM);
        
    }

    public List<SocketModel> getList() {
        return messages;
    }
    
}
消息管理

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
//消息管理用于分发,消息管理器
public class MessageManager : MonoBehaviour {
	private LoginHandler login;
	private UserHandler user;
	private MapHandler map;
	// Use this for initialization
	void Start () {
		login=GetComponent<LoginHandler>();
		user=GetComponent<UserHandler>();
		map=GetComponent<MapHandler>();
	}
	
	// Update is called once per frame
	void Update () {
		List<SocketModel> list=NetWorkScript.getInstance().getList();
		for(int i=0;i<8;i++){

			if(list.Count>0){
				//Debug.Log("onmessage");
				SocketModel model=list[0];
				//xiaoxichhuanru
				OnMessage(model);
				//yichudiyitiaoxiaoxi
				list.RemoveAt(0);
			}else{
				//Debug.Log("messmaneer");
				break;
			}
		}
	}
	public void OnMessage(SocketModel model){
		Debug.Log("model"+model.type);
//		if(model.type==520093696){
//			login.OnMessage(model);
//		}
		switch(model.type){
		case Protocol.LOGIN:
			login.OnMessage(model);
			break;
		case Protocol.USER:
			user.OnMessage(model);
			break;
		case Protocol.MAP:
			map.OnMessage(model);
			break;
		default:
			WindowConstans.windowList.Add(WindowConstans.SOCKET_TYPE_FAIL);
			break;

		}
	}


}
using UnityEngine;
using System.Collections;

public class LoginHandler : MonoBehaviour {

	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
	
	}
	public void OnMessage(SocketModel model){

		switch(model.command){
		case LoginProtocol.LOGIN_SRES:
			//Debug.Log("chuli消息"+model.Command);
			loginResult(model.message);
			break;
		case LoginProtocol.RES_SRES:
			RegResult(model.message);
			break;
		}
	}
	private void loginResult(string message){
		Debug.Log(message);
		StringDTO dto=Coding<StringDTO>.decode(message);
		GameInfo.ACC_ID=dto.value;
		if(dto.value==null||dto.value==string.Empty){
			WindowConstans.windowList.Add(WindowConstans.LOGIN_FAIL);
		}else{
			GameInfo.ACC_ID=dto.value;
			//GameInfo.GAME_STATE=GameState.LOADING;
			BroadcastMessage ("Loading",1);
		}

	}

	private void RegResult(string message){
		Debug.Log(message);
		BoolDTO dto=Coding<BoolDTO>.decode(message);
		if(dto.value){
			WindowConstans.windowList.Add(WindowConstans.ACC_REG_OK);
		}else{
			WindowConstans.windowList.Add(WindowConstans.ACC_REG_FAIL);

		}
	}

}
using UnityEngine;
using System.Collections;

public class BoolDTO {
	public bool value;
	public BoolDTO(){}
	public BoolDTO(bool v){
		this.value=v;
	}

}
运行,因为服务器使用的go语言,所以我们用liteide打开




using UnityEngine;
using System.Collections;
using LitJson;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class Coding<T> {
	public static string encode(T model){
		return JsonMapper.ToJson(model);
	}
	public static T decode(string message){
		return JsonMapper.ToObject<T>(message);
	}

}



启动服务器


全部的代码我就不做说明了,因为那是个很大的话题,可能篇幅要比仙剑demo还要大,这里就不找麻烦了,需要可以去看网上的一套免费课程,只不过那个课程没有提供源码和工程样例而已。

这里贴出工程地址(提取码:852e)

点我下载


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章