[ET框架学习]理解Socket

什么是socket

Socket(套接字)是应用层与TCP/IP协议族通信的中间软件抽象层,简单来说它是一组接口,也就是一套供应用程序调用的API。
Socket把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,只需要使用Socket提供的API接口就可以了,至于说如何让数据变成符合指定的网络协议的传输要求,Socket会自行完成。

个人理解

因为对Socket通信的流程仍然比较陌生,因此我搜索了网上的资料sh简单的socket通信流程。
学习自C#版 Socket编程(最简单的Socket通信功能)
在这里插入图片描述

服务端脚本

//Server.cs
using System.Net;
using System.Net.Sockets;
using System.Text;

public class Server
{
    public static void Main(string[] args)
    {
        int port = 2000;
        string host="127.0.0.1";

        ///创建终结点
        IPAddress ip = IPAddress.Parse(host);         //将字符串IP地址解析成IPAddress实例
        IPEndPoint ipe = new IPEndPoint(ip, port);    //用指定的端口和ip初始化IPEndPoint类的新实例

        ///创建Socket并开始监听
        #region
        //AddressFamily.InterNetwork表示套接字使用IPv4,InterNetworkV6使用IPv6
        //SocketType.Stream流套接字, 对应TCP协议.   SocketType.Dgram对应udp
        #endregion
        Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        s.Bind(ipe);         //绑定EndPoint对象(2000端口和IP地址)
        s.Listen(0);         //开始监听
        Console.WriteLine("等待客户端连接");

        ///接收client连接,为此连接建立新的socket,并接收信息
        Socket temp = s.Accept();
        Console.WriteLine("建立连接");
        string recvStr = "";
        byte[] recvBytes = new byte[1024];
        int bytes;
        bytes = temp.Receive(recvBytes, recvBytes.Length, 0);//返回值表示接收到的数据量
        recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
        Console.WriteLine("server get message:{0}", recvStr);

        ///给client端返回信息
        string sendStr = "Ok!Client send message successful(Server)";
        byte[] bs = Encoding.ASCII.GetBytes(sendStr);
        temp.Send(bs, bs.Length, 0);
        
        ///释放socket连接
        temp.Close();
        s.Close();
        Console.ReadLine();
    }
}

客户端脚本

//Client.cs
using System.Net;
using System.Net.Sockets;
using System.Text;

public class Client
{
    public static void Main(string[] args)
    {
        try
        {
            int port = 2000;
            string host = "127.0.0.1";
            ///创建终结点EndPoint
            IPAddress ip = IPAddress.Parse(host);
            IPEndPoint ipe = new IPEndPoint(ip, port); //把ip和端口转化为IPEndPoint实例

            ///创建socket并连接到服务器
            Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            Console.WriteLine("Conecting...");
            c.Connect(ipe);

            ///向服务端发送信息
            string sendStr = "Hello!This is a socket test(Client)";
            byte[] bs = Encoding.ASCII.GetBytes(sendStr); //将字符串转换为 ASCII 编码的字节数组。
            Console.WriteLine("Send Messege");
            c.Send(bs, bs.Length, 0);

            ///接受从服务端返回的信息
            string recvStr = "";
            byte[] recvBytes = new byte[1024];
            int bytes;
            bytes = c.Receive(recvBytes, recvBytes.Length, 0);
            recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
            Console.WriteLine("client get message:{0}", recvStr);
            ///记得用完Socket要关闭
            c.Close();
        }
        catch(ArgumentException e)//表示方法参数为空引发的异常
        {
            Console.WriteLine("argumentNullException:{0}",e);
        }
        catch(SocketException e) //server端未启动
        {
            Console.WriteLine("SocketException:{0}", e);
        }
        Console.WriteLine("Press Enter to Exit");
        Console.ReadLine();
    }
}

运行截图
在这里插入图片描述

在ET中的使用

流程和上面差不多。
在这里插入图片描述
我是这样理解的:

  1. accountSession = zoneScene.GetComponent<NetKcpComponent>().Create(NetworkHelper.ToIPEndPoint(address)); 首先创建一个IPEndPoint对象
	public static IPEndPoint ToIPEndPoint(string address)
		{
			int index = address.LastIndexOf(':');
			string host = address.Substring(0, index);//获取IP地址
			string p = address.Substring(index + 1); //获取端口号
			int port = int.Parse(p);
			return ToIPEndPoint(host, port);
		}
  1. 然后建立与服务器端的会话
        //建立一个会话
        public static Session Create(this NetKcpComponent self, IPEndPoint realIPEndPoint)
        {
            long channelId = RandomHelper.RandInt64();
            Session session = self.AddChildWithId<Session, AService>(channelId, self.Service);
            session.RemoteAddress = realIPEndPoint;
            session.AddComponent<SessionIdleCheckerComponent, int>(NetThreadComponent.checkInteral);
            
            //会创建一个TChannel对象,TChannel会建立一个和服务器端连接的socket
            //通过sessionId找到TChannel,继而找到socket
            //因此可以通过session向socket写入数据
            self.Service.GetOrCreate(session.Id, realIPEndPoint);

            return session;
        }

可以看到在TChannel的构造函数中创建了一个socket实例。

	public TChannel(long id, IPEndPoint ipEndPoint, TService service)
		{
			this.ChannelType = ChannelType.Connect;
			this.Id = id;
			this.Service = service;
			this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			this.socket.NoDelay = true;
			this.parser = new PacketParser(this.recvBuffer, this.Service);
			this.innArgs.Completed += this.OnComplete;
			this.outArgs.Completed += this.OnComplete;

			this.RemoteAddress = ipEndPoint;
			this.isConnected = false;
			this.isSending = false;
			//将回调push到主线程处理
			this.Service.ThreadSynchronizationContext.PostNext(this.ConnectAsync);
		}
  1. 建立会话后,客户端向服务器端发送与一条请求。
a2C_LoginAccount = (A2C_LoginAccount)await accountSession.Call(new C2A_LoginAccount() { AccountName = account, Password = password });
  1. 服务器端处理客户端发送的请求。
[FriendClass(typeof(Account))]
public class C2A_LoginAccountHandler : AMRpcHandler<C2A_LoginAccount, A2C_LoginAccount>
{
    protected override async ETTask Run(Session session, C2A_LoginAccount request, A2C_LoginAccount response, Action reply)
    {
        if (session.DomainScene().SceneType != SceneType.Account)
        {
            Log.Error($"请求的scene错误,当前scene为{session.DomainScene().SceneType}");
            session?.Dispose(); //请求的游戏服务器进程就是错误的,直接dispose
            return;
        }

        //如果不移除,session将会断开
        session.RemoveComponent<SessionAcceptTimeoutComponent>(); //移除检测组件

        ===以下省略一大坨处理逻辑===

        await ETTask.CompletedTask;
        }
    }
}
  1. 客户端处理服务器端返回的数据
a2C_LoginAccount = (A2C_LoginAccount)await accountSession.Call(new C2A_LoginAccount() { AccountName = account, Password = password });
//登录成功
if (a2C_LoginAccount.Error != ErrorCode.ERR_Success) 
{
    accountSession?.Dispose();
    return a2C_LoginAccount.Error;
}
//登录失败
else{
	.......
}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Unity ET框架是一套双端框架,可以同时支持前端和后端开发。它提供了一些特色功能,比如ET版本的ECS和异步模块,以及双端网络模块。使用ET框架可以提高双端开发的效率,因为前后端的代码可以共享。然而,需要注意的是,ET框架限制了后端只能使用C#开发语言。此外,ET框架的功能并不是非常完整和精细,特别是前端的框架部分,可能只能作为一个建议的demo使用,无法满足商业项目的需求。\[1\] 相比之下,GF框架是一套比较成熟、完整的游戏框架,适用于任何游戏引擎。GF框架提供了几乎所有在Unity开发游戏中可能用到的模块,结构清晰、耦合度低。然而,由于GF框架的完整性,学习成本可能会比较高,需要一定的适应时间。\[2\] 总的来说,ET框架更适合有经验的小团队或个人游戏开发者,尤其是那些熟悉C#语言的开发者。而GF框架则更适合需要一个完整、成熟的游戏框架的开发团队。选择哪个框架取决于团队的需求和开发经验。 #### 引用[.reference_title] - *1* *2* *3* [Unity 游戏框架之GameFramework和ET对比](https://blog.csdn.net/qq563129582/article/details/106993157)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值