tcp通信 unity3d_unity3d tcp连接 - CSDN
  • 转自:https://blog.csdn.net/hiramtan/article/details/72621787开源地址:https://github.com/hiramtan/HiSocket_unityHiSocket_unity如何使用可以从此链接下载最新的unity package: 功能Tcp socketUdp socket可...

    转自:https://blog.csdn.net/hiramtan/article/details/72621787

    开源地址:https://github.com/hiramtan/HiSocket_unity

    HiSocket_unity


    如何使用

    可以从此链接下载最新的unity package: Github Releases


    功能

    • Tcp socket
    • Udp socket
    • 可伸缩字节表
    • 高性能字节块缓冲区
    • 消息注册和回调
    • 二进制字节消息封装
    • Protobuf消息封装
    • AES消息加密

    详情

    • Tcp和Udp都是采用主线程异步连接的方式(避免主线程阻塞).
    • 启动发送线程和接收线程处理数据传输(提高性能).
    • 供用户调用发送或接受数据的API在主线程中(方便直接操作unity的组件)
    • 监听连接事件获得当前的连接状态.
    • 监听接收事件获得接收的数据.
    • 存在字节数组队列,方便用来测试和数据重发.
    • 高性能字节缓冲区避免内存空间重复申请,减少GC.
    • 如果使用Tcp协议需要实现IPackage接口处理粘包拆包.
    • Ping接口因为mono底层的bug会在.net2.0平台报错(.net 4.6 没有问题,或者也可以使用unity的接口获得Ping,工程中有示例代码)

    细节

    • Tcp 
      Transmission Control Protocol

      • Tcp connection 
        Tcp协议传输字节流,用户需要分割字节流获得正确的数据包,当创建一个tcp协议的socket时,需要传入一个Package对象来封包和解包.

        private IPackage _packer = new Packer();
        void Test()
        {
         _tcp = new TcpConnection(_packer);
        }
        
        public class Packer : IPackage
        {
            public void Unpack(IByteArray reader, Queue<byte[]> receiveQueue)
            {
               //add your unpack logic here
           }
        
           public void Pack(Queue<byte[]> sendQueue, IByteArray writer)
           {
               // add your pack logic here
           }
        }
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
      • 连接

        _tcp.Connect("127.0.0.1", 7777);
        • 1
      • 断开连接 
        当不再运行时需要主动调用接口断开与服务器的连接(比如响应unity的onapplicationquit执行时)

        void OnApplicationQuit()
        {
            _tcp.DisConnect();
        }
        • 1
        • 2
        • 3
        • 4
      • 连接状态变化 
        如果想获取当前的连接状态,可以订阅连接状态事件.

        void Test()
        {
            _tcp.StateChangeEvent += OnState;
        }
        void OnState(SocketState state)
        {
            Debug.Log("current state is: " + state);
            if (state == SocketState.Connected)
            {
                Debug.Log("connect success");
                //can send or receive message
            }
            else if (state == SocketState.DisConnected)
            {
                Debug.Log("connect failed");
            }
            else if (state == SocketState.Connecting)
            {
                Debug.Log("connecting");
            }
        }
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
      • 发送消息

        void Test()
        {
            var bytes = BitConverter.GetBytes(100);
            _tcp.Send(bytes);
        }
        • 1
        • 2
        • 3
        • 4
        • 5
      • 接受消息 
        You can regist receiveevent and when message come from server, this event will be fire.

            void Test()
            {
                _tcp.ReceiveEvent += OnReceive;
            }
            void OnReceive(byte[] bytes)
            {
                Debug.Log("receive msg: " + BitConverter.ToInt32(bytes, 0));
            }
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
      • 封包和解包 
        最初创建连接时我们定义了一个packer来分割数据包,当发送消息时我们在数据头部插入消息长度/当接收到消息时我们根据头部的消息长度获得数据包的大小.

        private bool _isGetHead = false;
        private int _bodyLength;
        public void Unpack(IByteArray reader, Queue<byte[]> receiveQueue)
        {
            if (!_isGetHead)
            {
                if (reader.Length >= 2)//2 is example, get msg's head length
                {
                    var bodyLengthBytes = reader.Read(2);
                    _bodyLength = BitConverter.ToUInt16(bodyLengthBytes, 0);
                }
                else
                {
                    if (reader.Length >= _bodyLength)//get body
                    {
                        var bytes = reader.Read(_bodyLength);
                        receiveQueue.Enqueue(bytes);
                        _isGetHead = false;
                    }
                }
            }
        }
        public void Pack(Queue<byte[]> sendQueue, IByteArray writer)
        {
            var bytesWaitToPack = sendQueue.Dequeue();
            UInt16 length = (UInt16)bytesWaitToPack.Length;//get head lenth
            var bytesHead = BitConverter.GetBytes(length);
            writer.Write(bytesHead);//write head
            writer.Write(bytesWaitToPack);//write body
        }
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
    • Udp

      • Udp connection 
        如果创建upd连接,需要指定发送接收缓冲区大小.

        _udp = new UdpConnection(1024);
        • 1
    • Ping

      public int PingTime;
      private Ping p;
      private float timeOut = 1;
      private float lastTime;
      void Start()
      {
          StartCoroutine(Ping());
      }
      IEnumerator Ping()
      {
          p = new Ping("127.0.0.1");
          lastTime = Time.realtimeSinceStartup;
          while (!p.isDone && Time.realtimeSinceStartup - lastTime < 1)
          {
              yield return null;
          }
          PingTime = p.time;
          p.DestroyPing();
          yield return new WaitForSeconds(1);
          StartCoroutine(Ping());
      }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
    • 消息注册
    • Protobuf
    • 字节消息
    • 加密

    Tcp Example

    Tcp 协议提供可靠有序的流字节传输,用户需要自己分割数据,在这个框架中可以继承IPackage接口来实现.

        private ITcp _tcp;
        private IPackage _packer = new Packer();
        // Use this for initialization
        void Start()
        {
            _tcp = new TcpConnection(_packer);
            _tcp.StateChangeEvent += OnState;
            _tcp.ReceiveEvent += OnReceive;
            Connect();
        }
        void Update()
        {
            _tcp.Run();
        }
    
        void Connect()
        {
            _tcp.Connect("127.0.0.1", 7777);
        }
        // Update is called once per frame
    
        void OnState(SocketState state)
        {
            Debug.Log("current state is: " + state);
            if (state == SocketState.Connected)
            {
                Debug.Log("connect success");
                Send();
            }
            else if (state == SocketState.DisConnected)
            {
                Debug.Log("connect failed");
            }
            else if (state == SocketState.Connecting)
            {
                Debug.Log("connecting");
            }
        }
        void OnApplicationQuit()
        {
            _tcp.DisConnect();
        }
        void Send()
        {
            for (int i = 0; i < 10; i++)
            {
                var bytes = BitConverter.GetBytes(i);
                Debug.Log("send message: " + i);
                _tcp.Send(bytes);
            }
        }
        void OnReceive(byte[] bytes)
        {
            Debug.Log("receive msg: " + BitConverter.ToInt32(bytes, 0));
        }
        public class Packer : IPackage
        {
            public void Unpack(IByteArray reader, Queue<byte[]> receiveQueue)
            {
                //add your unpack logic here
                if (reader.Length >= 1024)//1024 is example, it's msg's length
                {
                    var bytesWaitToUnpack = reader.Read(1024);
                    receiveQueue.Enqueue(bytesWaitToUnpack);
                }
            }
    
            public void Pack(Queue<byte[]> sendQueue, IByteArray writer)
            {
                var bytesWaitToPack = sendQueue.Dequeue();
                // add your pack logic here
                //
    
                writer.Write(bytesWaitToPack);
            }
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    Udp Example

    User Datagram Protocol

    Udp协议提供不可靠的报文消息,用户无法知道当前连接状态,但是消息包时完整的.

        private UdpConnection _udp;
        // Use this for initialization
        void Start()
        {
            _udp = new UdpConnection(1024);
            _udp.ReceiveEvent += OnReceive;
            Connect();
            Send();
        }
        void Connect()
        {
            _udp.Connect("127.0.0.1", 7777);
        }
        // Update is called once per frame
        void Update()
        {
            _udp.Run();
        }
        void Send()
        {
            for (int i = 0; i < 10; i++)
            {
                var bytes = BitConverter.GetBytes(i);
                _udp.Send(bytes);
                Debug.Log("send message: " + i);
            }
        }
        private void OnApplicationQuit()
        {
            _udp.DisConnect();
        }
        void OnReceive(byte[] bytes)
        {
            Debug.Log("receive bytes: " + BitConverter.ToInt32(bytes, 0));
        }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    Message Registration Example

        void RegistMsg()
        {
            MsgRegister.Regist("10001", OnMsg_Bytes);
            MsgRegister.Regist("10002", OnMsg_Protobuf);
        }
    
        void OnMsg_Bytes(IByteArray byteArray)
        {
            var msg = new MsgBytes(byteArray);
            int getInt = msg.Read<int>();
        }
    
        void OnMsg_Protobuf(IByteArray byteArray)
        {
            var msg = new MsgProtobuf(byteArray);
            GameObject testClass = msg.Read<GameObject>();//your class's type
            var testName = testClass.name;
        }
    展开全文
  • 自己设计的一套实用的针对中小型网络游戏的网络通信框架

    大家好,我是FoldCc,今天给大家分享一下自己设计并且经常用到的一个网络通信框架---客户端

    经过自己的实践,发现这套框架在应对一些中小型手游还是比较稳定使用的,整体结构也比较简单,但是特别实用,唯一要注意一点的是在开发网络通信时,一定要注意多线程争用资源的问题。

    下面我为大家详细介绍一下:

    首先最核心的是Socket连接器 它的功能主要有4个

    》向服务器发起连接请求

    》一个能够返回已经连接服务器的Socket的方法(仅用于之后开启接收和发送消息线程)

    》判断当前是否连接正常

    》断开服务器连接

    当连接器连接成功后会自动创建两个线程,分别用来接收和发送,(至于为什么要单独分开成两个,是因为在实际应用中一个线程处理这两个效率上低,容易出问题,并且理论上来说一个线程同时处理发送和接收也有点不合理)为了防止接收和发送线程在处理消息可能出现效率跟不上的问题,我设置了两个消息队列,分别用来装发送的消息和接收的消息,其中接收的消息通过消息分类器分类到不同队列中,这里需要注意的一点是,接收消息需要做粘包处理!说通俗一点就是判断消息的完整性,这里我为所有消息都加了一个特定的消息头 和消息尾 用来判断消息的完整性,至于消息头和消息尾的内容由自己设计,最好是不常使用的一些特殊字符,防止遇到和内容相同的情况。

    两个线程则只负责将收到的消息往队列中存储以及将发送队列的消息按顺序发送就行了,消息分类会单独去对消息进行分类并存放到对应队列中。

    下面是这一套框架的流程图,如果有用大家帮忙转载哦!大笑

    展开全文
  • unity3d的socket通信,有人会做吗?这两天做一个场景,需要用外部程序提供的数据来驱动场景,有没有大神会做呀?
  • Unity3D上进行TCP Client的创建与通讯简介代码 简介 Unity3D版本: 2018.3.0f2 Personal Visual Studio版本:2017 在Unity3D上连接TCP Server建立通讯 建立通讯后进行双向数据传输 代码 创建文件TCPUDPSocket.cs ...

    在Unity3D上进行TCP Client的创建与通讯

    简介

    Unity3D版本: 2018.3.0f2 Personal
    Visual Studio版本:2017

    在Unity3D上连接TCP Server建立通讯
    建立通讯后进行双向数据传输

    代码

    创建文件TCPUDPSocket.cs

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.IO;
    using System.Net.Sockets;
    using System.Text;
    
    public class TCPUDPSocket : MonoBehaviour
    {
        NetworkStream sendStream;
        TcpClient client;
        bool flag = false;
        public void Start_TCPClient(string ip, int port)
        {
            client = new TcpClient(ip, port);
            sendStream = client.GetStream();
            flag = true;
        }
    
        public void Close_TCPClient()
        {
            sendStream.Close();
            client.Close();
            flag = false;
        }
    
        public void Write_TCPClient(string data)
        {
            if (flag == false)
                return;
            byte[] sendBytes = Encoding.Default.GetBytes(data);
            sendStream.Write(sendBytes, 0, sendBytes.Length);
        }
    
        public string Read_TCPClient()
        {
            if (flag == false)
                return "";
            byte[] readbyte = new byte[sendStream.Length];
            sendStream.Read(readbyte, 0, (int)sendStream.Length);
            return Encoding.ASCII.GetString(readbyte);
        }
        // Start is called before the first frame update
        void Start()
        {
            Start_TCPClient("192.168.199.231",2333);
        }
    
        // Update is called once per frame
        void Update()
        {
            
        }
    
       
    }
    
    

    根据需要可以进行发送与接收函数的调用,函数功能很简单,看名字就知道

    展开全文
  • 简单的基于Unity的客户端连接服务器端,相互发送一次数据,文档描述位于http://blog.sina.com.cn/s/blog_1322690230102y3l4.html
  • 前言:  在开始编写代码之前,我们首先需要明确:联网方式、联网步骤...我们这里使用的通信模式是Socket强连接的通信方式,并且使用C#作为编程语言,其实与.NET的Socket通信是一致的。   一、设计思想:  为...

    前言:

            在开始编写代码之前,我们首先需要明确:联网方式联网步骤数据收发以及协议数据格式

            当然在设计时也应该减低代码的耦合性,尽量使得网络层可以在其他地方进行复用,这就需要我们进行接口式的开发。我们这里使用的通信模式是Socket强连接的通信方式,并且使用C#作为编程语言,其实与.NET的Socket通信是一致的。

     

    一、设计思想:

            为了方便测试,我直接使用C#写的一个控制台应用,作为服务器,等待客户端的连接,然后使用Unity建立Socket客户端去连接服务器,进行简单的数据通信。这么设计的原因是都基于.net进行开发,也方便理解。

     

    二、实现步骤:

            对于网络通信有所了解的都应该知道,数据在网络传输的格式必须以字节流的形式进行,那么免不了要对字节流进行写入和读出操作,为了方便后面的操作,我们有必要封装一个读写字节流的操作类,在这里我定义了一个字节流的操作类ByteBuffer类,用于将各个类型数据写入流中,也可从字节流中读取各种类型的数据:

     

    using System.IO;
    using System.Text;
    using System;
    
    namespace Net {
        public class ByteBuffer {
            MemoryStream stream = null;
            BinaryWriter writer = null;
            BinaryReader reader = null;
    
            public ByteBuffer() {
                stream = new MemoryStream();
                writer = new BinaryWriter(stream);
            }
    
            public ByteBuffer(byte[] data) {
                if (data != null) {
                    stream = new MemoryStream(data);
                    reader = new BinaryReader(stream);
                } else {
                    stream = new MemoryStream();
                    writer = new BinaryWriter(stream);
                }
            }
    
            public void Close() {
                if (writer != null) writer.Close();
                if (reader != null) reader.Close();
    
                stream.Close();
                writer = null;
                reader = null;
                stream = null;
            }
    
            public void WriteByte(byte v) {
                writer.Write(v);
            }
    
            public void WriteInt(int v) {
                writer.Write((int)v);
            }
    
            public void WriteShort(ushort v) {
                writer.Write((ushort)v);
            }
    
            public void WriteLong(long v) {
                writer.Write((long)v);
            }
    
            public void WriteFloat(float v) {
                byte[] temp = BitConverter.GetBytes(v);
                Array.Reverse(temp);
                writer.Write(BitConverter.ToSingle(temp, 0));
            }
    
            public void WriteDouble(double v) {
                byte[] temp = BitConverter.GetBytes(v);
                Array.Reverse(temp);
                writer.Write(BitConverter.ToDouble(temp, 0));
            }
    
            public void WriteString(string v) {
                byte[] bytes = Encoding.UTF8.GetBytes(v);
                writer.Write((ushort)bytes.Length);
                writer.Write(bytes);
            }
    
            public void WriteBytes(byte[] v) {
                writer.Write((int)v.Length);
                writer.Write(v);
            }
    
            public byte ReadByte() {
                return reader.ReadByte();
            }
    
            public int ReadInt() {
                return (int)reader.ReadInt32();
            }
    
            public ushort ReadShort() {
                return (ushort)reader.ReadInt16();
            }
    
            public long ReadLong() {
                return (long)reader.ReadInt64();
            }
    
            public float ReadFloat() {
                byte[] temp = BitConverter.GetBytes(reader.ReadSingle());
                Array.Reverse(temp);
                return BitConverter.ToSingle(temp, 0);
            }
    
            public double ReadDouble() {
                byte[] temp = BitConverter.GetBytes(reader.ReadDouble());
                Array.Reverse(temp);
                return BitConverter.ToDouble(temp, 0);
            }
    
            public string ReadString() {
                ushort len = ReadShort();
                byte[] buffer = new byte[len];
                buffer = reader.ReadBytes(len);
                return Encoding.UTF8.GetString(buffer);
            }
    
            public byte[] ReadBytes() {
                int len = ReadInt();
                return reader.ReadBytes(len);
            }
    
            public byte[] ToBytes() {
                writer.Flush();
                return stream.ToArray();
            }
    
            public void Flush() {
                writer.Flush();
            }
        }
    }

     

            使用此操作类进行读写数据的操作范例如下:

     

    • 读取数据:
           //result是字节数组byte[],从中读取两个int类型的数据
            ByteBuffer buff = new ByteBuffer(result);
            int len = buff.ReadShort();
            int protoId = buff.ReadShort();
    • 写入数据:
            //result是字节数组byte[],从写入两个不同类型的数据
            ByteBuffer buff = new ByteBuffer();
            int protoId = ProtoDic.GetProtoIdByProtoType(0);
            buff.WriteShort((ushort)protoId);
            buff.WriteBytes(ms.ToArray());
            byte[] result = buff.ToBytes();

     

     

    1.服务器创建:

            在VS中新建一个C#控制台应用,新建项目完成后将上面定义的ByteBuffer.cs类导入工程中,然后开始在入口类Program中开始创建Socket服务器的逻辑。

            先引入必要的命名空间:

     

    using System.Net;
    using System.Net.Sockets;
    using System.Threading;

            基本的步骤如下:

     

    • 创建一个服务器Socket对象,并绑定服务器IP地址和端口号;
            private const int port = 8088;
            private static string IpStr = "127.0.0.1";
            private static Socket serverSocket;
    
            static void Main(string[] args)
            {
                IPAddress ip = IPAddress.Parse(IpStr);
                IPEndPoint ip_end_point = new IPEndPoint(ip, port);
                //创建服务器Socket对象,并设置相关属性
                serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //绑定ip和端口
                serverSocket.Bind(ip_end_point);
                //设置最长的连接请求队列长度
                serverSocket.Listen(10);
                Console.WriteLine("启动监听{0}成功", serverSocket.LocalEndPoint.ToString());
            }

            完成上述代码之后,已经能正常启动一个服务器Socket,但是还没有处理连接监听逻辑和数据接收,所以运行应用会出现一闪就关掉的情况。

    • 启动一个线程,并在线程中监听客户端的连接,为每个连接创建一个Socket对象;
    • 创建接受数据和发送数据的方法。

            完整的代码如下:

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading.Tasks;
    using System.Net;
    using System.Threading;
    using Net;
    using System.IO;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            private static byte[] result = new byte[1024];
            private const int port = 8088;
            private static string IpStr = "127.0.0.1";
            private static Socket serverSocket;
    
            static void Main(string[] args)
            {
                IPAddress ip = IPAddress.Parse(IpStr);
                IPEndPoint ip_end_point = new IPEndPoint(ip, port);
                //创建服务器Socket对象,并设置相关属性
                serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //绑定ip和端口
                serverSocket.Bind(ip_end_point);
                //设置最长的连接请求队列长度
                serverSocket.Listen(10);
                Console.WriteLine("启动监听{0}成功", serverSocket.LocalEndPoint.ToString());
                //在新线程中监听客户端的连接
                Thread thread = new Thread(ClientConnectListen);
                thread.Start();
                Console.ReadLine();
            }
    
            /// <summary>
            /// 客户端连接请求监听
            /// </summary>
            private static void ClientConnectListen()
            {
                while (true)
                {
                    //为新的客户端连接创建一个Socket对象
                    Socket clientSocket = serverSocket.Accept();
                    Console.WriteLine("客户端{0}成功连接", clientSocket.RemoteEndPoint.ToString());
                    //向连接的客户端发送连接成功的数据
                    ByteBuffer buffer = new ByteBuffer();
                    buffer.WriteString("Connected Server");
                    clientSocket.Send(WriteMessage(buffer.ToBytes()));
                    //每个客户端连接创建一个线程来接受该客户端发送的消息
                    Thread thread = new Thread(RecieveMessage);
                    thread.Start(clientSocket);
                }
            }
    
            /// <summary>
            /// 数据转换,网络发送需要两部分数据,一是数据长度,二是主体数据
            /// </summary>
            /// <param name="message"></param>
            /// <returns></returns>
            private static byte[] WriteMessage(byte[] message)
            {
                MemoryStream ms = null;
                using (ms = new MemoryStream())
                {
                    ms.Position = 0;
                    BinaryWriter writer = new BinaryWriter(ms);
                    ushort msglen = (ushort)message.Length;
                    writer.Write(msglen);
                    writer.Write(message);
                    writer.Flush();
                    return ms.ToArray();
                }
            }
    
            /// <summary>
            /// 接收指定客户端Socket的消息
            /// </summary>
            /// <param name="clientSocket"></param>
            private static void RecieveMessage(object clientSocket)
            {
                Socket mClientSocket = (Socket)clientSocket;
                while (true)
                {
                    try
                    {
                        int receiveNumber = mClientSocket.Receive(result);
                        Console.WriteLine("接收客户端{0}消息, 长度为{1}", mClientSocket.RemoteEndPoint.ToString(), receiveNumber);
                        ByteBuffer buff = new ByteBuffer(result);
                        //数据长度
                        int len = buff.ReadShort();
                        //数据内容
                        string data = buff.ReadString();
                        Console.WriteLine("数据内容:{0}", data);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        mClientSocket.Shutdown(SocketShutdown.Both);
                        mClientSocket.Close();
                        break;
                    }
                }
            }
        }
    }

     

     

    2.客户端创建:

            客户端连接服务器的逻辑相对简单一些,跟服务器一样,先把ByteBuffer类导入到工程中,基本步骤如下:

     

    • 创建一个Socket对象,这个对象在客户端是唯一的,可以理解为单例模式;
    • 使用上面创建Socket连接指定服务器IP和端口号;
    • 接收服务器数据和发送数据给服务器。

            先创建一个ClientSocket类用于管理Socket的一些方法:连接服务器、接受数据和发送数据等:

    using UnityEngine;
    using System.Collections;
    using System.Net;
    using System.Net.Sockets;
    using System.IO;
    
    namespace Net
    {
        public class ClientSocket
        {
            private static byte[] result = new byte[1024];
            private static Socket clientSocket;
            //是否已连接的标识
            public bool IsConnected = false;
    
            public ClientSocket(){
                clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            }
    
            /// <summary>
            /// 连接指定IP和端口的服务器
            /// </summary>
            /// <param name="ip"></param>
            /// <param name="port"></param>
            public void ConnectServer(string ip,int port)
            {
                IPAddress mIp = IPAddress.Parse(ip);
                IPEndPoint ip_end_point = new IPEndPoint(mIp, port);
    
                try {
                    clientSocket.Connect(ip_end_point);
                    IsConnected = true;
                    Debug.Log("连接服务器成功");
                }
                catch
                {
                    IsConnected = false;
                    Debug.Log("连接服务器失败");
                    return;
                }
                //服务器下发数据长度
                int receiveLength = clientSocket.Receive(result);
                ByteBuffer buffer = new ByteBuffer(result);
                int len = buffer.ReadShort();
                string data = buffer.ReadString();
                Debug.Log("服务器返回数据:" + data);
            }
    
            /// <summary>
            /// 发送数据给服务器
            /// </summary>
            public void SendMessage(string data)
            {
                if (IsConnected == false)
                    return;
                try
                {
                    ByteBuffer buffer = new ByteBuffer();
                    buffer.WriteString(data);
                    clientSocket.Send(WriteMessage(buffer.ToBytes()));
                }
                catch
                {
                    IsConnected = false;
                    clientSocket.Shutdown(SocketShutdown.Both);
                    clientSocket.Close();
                }
            }
    
            /// <summary>
            /// 数据转换,网络发送需要两部分数据,一是数据长度,二是主体数据
            /// </summary>
            /// <param name="message"></param>
            /// <returns></returns>
            private static byte[] WriteMessage(byte[] message)
            {
                MemoryStream ms = null;
                using (ms = new MemoryStream())
                {
                    ms.Position = 0;
                    BinaryWriter writer = new BinaryWriter(ms);
                    ushort msglen = (ushort)message.Length;
                    writer.Write(msglen);
                    writer.Write(message);
                    writer.Flush();
                    return ms.ToArray();
                }
            }
        }
    }
    

     

     

    三、样例测试:

    1.客户端测试:

            在Unity中写一个测试脚本TestSocket.cs,并将此脚本绑到当前场景的相机上:

     

    using UnityEngine;
    using System.Collections;
    using Net;
    
    public class TestSocket : MonoBehaviour {
    
    	// Use this for initialization
    	void Start () {
            ClientSocket mSocket = new ClientSocket();
            mSocket.ConnectServer("127.0.0.1", 8088);
            mSocket.SendMessage("服务器傻逼!");
        }
    	
    	// Update is called once per frame
    	void Update () {
    	
    	}
    }
    


    2.启动服务器:

            在Visual Studio中点击运行按钮,启动服务器:

            

            启动正常的话,会弹出一个窗口如下图所示:

            

     

    3.开始连接:

            在Unity中运行当前场景,查看输出日志,假如连接成功,输出如下:

            

            查看服务器窗口,发现双向通信都正常:

             

     

    四、总结:

            这里测试案例其实很简单,协议没有进行如何优化,单纯地发送字符串数据而已,假如针对复杂的数据的话,需要创建完整打包和解包协议数据的机制,而且必要时还需要对数据进行加密操作。


    微信公众号「何乐不为呢」,一个码农的技术笔记和唠叨。

    展开全文
  • Unity之前都是使用RPC来进行网络通信的,后来在Unity5中有了UNET,使得开发多人在线网络游戏变得非常简单。本文将会介绍使用新网络模块UNET开发游戏的简单方法。
  • 今年3D产品的工作中心主要集中在提高产品深度上,通过对竞争产品的分析,发现我们的缺陷在于多人在线与后台管理部分,多人在线使用unity自带的Network可以搞定,后台部分前段时间主要研究了下Sqlite。由于sqlite本身...
  • 本文介绍Android终端持续扫描AP信息并发送给服务器端的实现。首先基于TCP协议在Android终端和PC两端之间形成网络虚拟链路。使用ServerSocket创建TCP服务器端,然后在Android客户端...两个通信实体在建立虚拟链路之前,
  • 已入强化学习一个学期了,发现自己急需一个物理环境来进行训练机器人,前前后后参考过过许多环境,但是最后选择了Unity3D,这是因为其足够简单,不用费很大的功夫就可以建立一个简易的机器人,只需要编写C#脚本和...
  • 本次系列课程的目标是让Unity3D初学者掌握Unity3d的网络开发技术,课程重点将对TCP数据通信时如何对数据进行序列化和反序列化,如何解析数据包等重要知识点进行深入探讨。
  • protobuf-net - ing... 时间 2014-09-02 16:04:00 博客园-所有随笔区原文 http://www.cnblogs.com/123ing/p/3951642.html 原文:http://my.oschina.net/faint/blog/296785 第一部分 dll ...
  • nity内部封装了一个很高层次的网络接口,不过有时候并不需要那么复杂的功能,只是想实现简单的TCP网络连接,可以在unity里面用C#写tcp socket。 以下TCP连接是同步模式。 建立两个unity工程,编写脚本。 服务端 ...
  • 而在Unity3D的开发当中,Tcp通讯更是重中之重,不懂Tcp,日常开发工作就会变得尤为艰难甚至寸步难行。 本篇文章我就详细的记录一下我所了解的Unity中的Tcp通讯,并逐步去实现一个比较常用的Tcp通讯框架。 首先了解...
  • 最近由于项目需要,对Unity3D应用嵌入WPF应用进行了研究,并通过Socket实现了两者的通信。由于Unity3D在5.4.x版本后不再支持WebPlayer,所以并未使用UnityWebPlayer,另外考虑到我们原有的业务系统都是基于WPF的,...
  • Unity3D Socket通信 UDP

    2017-09-20 16:06:47
    图1 using System.Collections; using System.Collections.Generic; using UnityEngine; //使用Socket引用的命名空间 using System.Net.Sockets; //绑定端口号引用的命名空间 using System.Net;...
  • 今天研究了一天.终于把这套东西给搞通了.其实很简单.需要的代码也不是很多...就是中间走了不少弯路. ...var tcp = require("./LighterWebEngine/TCP"); tcp.CreateServer(10000, function(){ //
  • 客户端 using System.Text; using System.Net.Sockets; using System.Net; using UnityEngine; using UnityEngine.UI;...using System.Threading;...public class _GameManager : MonoBehaviour ... publ
1 2 3 4 5 ... 20
收藏数 903
精华内容 361
关键字:

tcp通信 unity3d