Unity——服务端和客户端

客户端

 

实现服务端基本逻辑

                1.创建套接字Socket(TCP)

 Socket socketTcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                2.用Bind方法将套接字与本地地址绑定

            try
            {
                IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
                socketTcp.Bind(ipPoint);
            }
            catch (Exception e)
            {
                Console.WriteLine("绑定报错" + e.Message);
                return;
            }

                3.用Listen方法监听

            socketTcp.Listen(1024);
            Console.WriteLine("服务端绑定监听结束,等待客户端连入");

                4.用Accept方法等待客户端连接

                5.建立连接,Accept返回新套接字

            Socket socketClient = socketTcp.Accept();
            Console.WriteLine("有客户端连入了");

                6.用Send和Receive相关方法收发数据

            //发送
            socketClient.Send(Encoding.UTF8.GetBytes("欢迎连入服务端"));
            //接受
            byte[] result = new byte[1024];
            //返回值为接受到的字节数
            int receiveNum = socketClient.Receive(result);
            Console.WriteLine("接受到了{0}发来的消息:{1}",
                socketClient.RemoteEndPoint.ToString(),
                Encoding.UTF8.GetString(result, 0, receiveNum));

                7.用Shutdown方法释放连接

socketClient.Shutdown(SocketShutdown.Both);

                8.关闭套接字

 socketClient.Close();

                实现服务端基本逻辑

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace NetTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //1.创建套接字Socket
            Socket socketTcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            
            //2.用Bind方法将套接字与本地地址绑定(注:这里用try、catch是为了防止端口号已经被使用了
            try
            {
                //指定服务器的IP地址和端口号
                IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
                socketTcp.Bind(ipPoint);
            }
            catch (Exception e)
            {
                Console.WriteLine("绑定报错" + e.Message);
                return;
            }

            //3.用Listen方法监听,参数代表可以接入客户端最大的数量
            socketTcp.Listen(1024);
            Console.WriteLine("服务端绑定监听结束,等待客户端连入");

            //4.用Accept方法等待客户端连接
            //5.建立连接,Accept返回新套接字
            Socket socketClient = socketTcp.Accept();  //该函数的执行,会一直坚持到有客户端加入才会继续到下一步
            Console.WriteLine("有客户端连入了");

            //6.用Send和Receive相关方法收发数据
            //发送
            socketClient.Send(Encoding.UTF8.GetBytes("欢迎加入服务端"));
            //接收
            byte[] result = new byte[1024];
            //返回值为接受到的字节数
            int receiveNum = socketClient.Receive(result);
            Console.WriteLine("接受到了{0}发来的消息:{1}",
                               socketClient.RemoteEndPoint.ToString(),
                               Encoding.UTF8.GetString(result, 0, receiveNum));

            //7.用Shutdown方法释放连接
            socketClient.Shutdown(SocketShutdown.Both);

            //8.关闭套接字
            socketClient.Close();


            Console.WriteLine("按任意键退出");
            Console.ReadKey();
        }
            
    }
}

客户端

        实现客户端基本逻辑

                1.创建套接字Socket

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


                2.用Connect方法与服务端相连

        //确定服务端的IP和端口
        IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
        try
        {
            socket.Connect(ipPoint);
        }
        catch (SocketException e)
        {
            if (e.ErrorCode == 10061)
                print("服务器拒绝连接");
            else
                print("连接服务器失败" + e.ErrorCode);
            return;
        }


                3.用Send和Receive相关方法收发数据(客户端的 Connect、Send、Receive是会阻塞主线程的,要等到执行完毕才会继续执行后面的内容

        //接收数据
        byte[] receiveBytes = new byte[1024];
        int receiveNum = socket.Receive(receiveBytes);
        print("收到服务端发来的消息:" + Encoding.UTF8.GetString(receiveBytes, 0, receiveNum));

        //发送数据
        socket.Send(Encoding.UTF8.GetBytes("你好,我是唐老狮的客户端"));


                4.用Shutdown方法释放连接

 socket.Shutdown(SocketShutdown.Both);


                5.关闭套接字

 socket.Close();

        实现客户端基本逻辑

using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;

public class Lesson6 : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        //1.创建套接字Socket
        Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        //2.用Connect方法与服务端相连
        IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);  //这里面的IP地址和端口号指的是服务端的而不是客户端的
        try
        {
            socket.Connect(ipPoint);
        }
        catch(SocketException e)
        {
            if (e.ErrorCode == 10061)
                print("服务器拒绝连接");
            else
                print("连接服务器失败" + e.ErrorCode);
            return;
        }

        //3.用Send和Receive相关方法收发数据

        //接收数据
        byte[] receiveBytes = new byte[1024];
        int receiveNum = socket.Receive(receiveBytes);
        print("收到服务端发来的消息:" + Encoding.UTF8.GetString(receiveBytes, 0, receiveNum));

        //发送数据
        socket.Send(Encoding.UTF8.GetBytes("你好,我是客户端"));

        //4.用Shutdown方法释放连接
        socket.Shutdown(SocketShutdown.Both);

        //5.关闭套接字
        socket.Close();
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

服务端实现多个客户端的交换

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Test02
{
    class Program
    {
        //设置socket静态变量,方便在全局进行使用
        static Socket socket;

        //设置一个存放客户端的链表
        static List<Socket> clientSockets = new List<Socket>();

        static bool IsClose = false;

        static void Main(string[] args)
        {
            //1.建立Socket 绑定 监听
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
            socket.Bind(ipPoint);
            socket.Listen(1024);

            //2.等待客户端连接

            //开启多线程接收客户端的连接
            Thread acceptThread = new Thread(AcceptClientConnect);
            //线程的开启
            acceptThread.Start();

            //3.收发消息
            Thread receiveThread = new Thread(ReceiveMsg);
            receiveThread.Start();

            //4.关闭相关
            while (true)
            {
                Console.WriteLine(1);

                string input = Console.ReadLine();

                //定义一个关闭服务器,断开连接
                if(input == "Quit")
                {
                    IsClose = true;

                    //遍历关闭所有与客户端的连接
                    for(int i = 0; i < clientSockets.Count; i++)
                    {
                        clientSockets[i].Shutdown(SocketShutdown.Both);
                        clientSockets[i].Close();
                    }

                    //清空客户端数组
                    clientSockets.Clear();
                    IsClose = true;
                    Console.WriteLine("服务端已关闭");
                    break;
                }

                //定义一个规则 广播消息 就是让所有客户端收到服务端发送的消息
                else if (input.Substring(0, 2) == "B:")
                {
                    for (int i = 0; i < clientSockets.Count; i++)
                    {
                        clientSockets[i].Send(Encoding.UTF8.GetBytes(input.Substring(2)));
                    }
                }
            }
        }

        public static void AcceptClientConnect()
        {
            while (!IsClose)
            {
                Socket clientSocket = socket.Accept();
                clientSockets.Add(clientSocket);
                clientSocket.Send(Encoding.UTF8.GetBytes("欢迎加入服务端"));
            }
        }

        public static void ReceiveMsg()
        {
            Socket clientSocket;
            byte[] result = new byte[1024];
            int receiveNum;
            int i;

            //死循环,一直接收客户端的消息
            while (!IsClose)
            {
                //遍历整个客户端数组看是否有消息传入
                for(i = 0; i < clientSockets.Count; i++)
                {
                    clientSocket = clientSockets[i];

                    //判断该客户端是否返回长度大于0的消息
                    if(clientSocket.Available > 0)
                    {
                        //将从客户端接收到的消息存入字节当中,并且返回收到的字节数
                        receiveNum = clientSocket.Receive(result);
                        //使用线程池来处理接收到的消息
                        ThreadPool.QueueUserWorkItem(HandleMsg, (result, 0, receiveNum));
                    }
                }
            }
        }

        static void HandleMsg(object obj)
        {
            //将所有的传入的数据强制转换
            (Socket s, string str) info = ((Socket s, string str))obj;
            Console.WriteLine("收到客户端{0}发来的信息:{1}", info.s.RemoteEndPoint, info.str);
        }
    }
}

使用面向对象编程的思想封装服务端

        对客户端处理的部分

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Test04
{
    class ClientSocket
    {
        //记录当前通讯的客户端的编号和网络
        private static int CLIENT_BEGIN_ID = 1;
        public int clientID;
        public Socket socket;
        
        public ClientSocket(Socket socket)
        {
            this.clientID = CLIENT_BEGIN_ID;
            this.socket = socket;
            //每有一个客户端连入,编号就++
            ++CLIENT_BEGIN_ID;
        }

        /// <summary>
        /// 是否是连接状态
        /// </summary>
        public bool Connected => this.socket.Connected;

        //关闭与客户端的连接
        public void Close()
        {
            //如果客户端的网络连接不是空,就将它变为空
            if(socket != null)
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
                socket = null;
            }
        }

        //与客户端发送消息
        public void Send(string info)
        {
            //如果不为空就可以进行与客户端的消息发送
            if(socket != null)
            {
                try
                {
                    socket.Send(Encoding.UTF8.GetBytes(info));
                }
                catch(Exception e)
                {
                    Console.WriteLine("发送消息出错" + e.Message);
                    Close();
                }
            }
        }

        //接收客户端的发来的消息
        public void Receive()
        {
            //如果网络为空就进行返回
            if (socket == null)
                return;
            try
            {
                //如果传入的数据大于0
                if(socket.Available > 0)
                {
                    byte[] result = new byte[1024];
                    int receiveNum = socket.Receive(result);
                    //开启线程池一直监听客户端发来的消息
                    ThreadPool.QueueUserWorkItem(MsgHandle,Encoding.UTF8.GetString(result,0,receiveNum));
                }
            }catch(Exception e)
            {
                Console.WriteLine("收发消息出错" + e.Message);
                Close();
            }
        }

        private void MsgHandle(object obj)
        {
            string str = obj as string;
            Console.WriteLine("收到客户端{0}发来的消息:{1}", this.socket.RemoteEndPoint, str);
        }
    }
}

        服务端的开启和关闭

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Test04
{
    class ServerSocket
    {
        /// <summary>
        /// 服务端的Socket网络协议
        /// </summary>
        public Socket socket;

        //字典存储(id为字典编号,数据为客户端)
        public Dictionary<int, ClientSocket> clientDic = new Dictionary<int, ClientSocket>();

        private bool isClose;

        //开启服务器端
        public void Start(string ip,int port,int num)
        {
            isClose = false;
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse(ip), port);
            socket.Bind(ipPoint);
            socket.Listen(num);
            ThreadPool.QueueUserWorkItem(Accept);
            ThreadPool.QueueUserWorkItem(Receive);
        }

        public void Close()
        {
            isClose = true;
            foreach(ClientSocket client in clientDic.Values)
            {
                client.Close();
            }
            clientDic.Clear();

            socket.Shutdown(SocketShutdown.Both);
            socket.Close();
            socket = null;
        }

        //接受客户端的连入
        private void Accept(object obj)
        {
            while (!isClose)
            {
                try
                {
                    //连入一个客户端
                    Socket clientSocket = socket.Accept();
                    ClientSocket client = new ClientSocket(clientSocket);
                    client.Send("欢迎连入服务器");
                    clientDic.Add(client.clientID, client);
                }
                catch(Exception e)
                {
                    Console.WriteLine("客户端连入报错" + e.Message);
                }
            }
        }

        //接受客户端的消息
        private void Receive(object obj)
        {
            while (!isClose)
            {
                if (clientDic.Count > 0)
                {
                    foreach (ClientSocket client in clientDic.Values)
                    {
                        client.Receive();
                    }
                }
            }
        }

        //广播消息
        public void Broadcast(string info)
        {
            foreach(ClientSocket client in clientDic.Values)
            {
                client.Send(info);
            }
        }
    }
}

        服务端的主程序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test04
{
    class Program
    {
        static void Main(string[] args)
        {
            ServerSocket socket = new ServerSocket();
            socket.Start("127.0.0.1", 8080, 1024);
            Console.WriteLine("服务端开启成功");

            while (true)
            {
                string input = Console.ReadLine();
                if(input == "Quit")
                {
                    socket.Close();
                }
                else if(input.Substring(0,2) == "B:")
                {
                    socket.Broadcast(input.Substring(2));
                }
            }
        }
    }
}

客户端实现

        

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

public class NetMgr : MonoBehaviour
{
    //通过单例让一个类只有一个实例
    private static NetMgr instance;

    public static NetMgr Instance => instance;

    //客户端的Socket
    private Socket socket;

    //用于发送消息的队列 公共的容器(线程) 主线程往里面放 发送线程从里面取
    private Queue<string> sendMsgQueue = new Queue<string>();
    //用于接受消息的对象 公共容器(线程) 子线程往里面放 主线程从里面取
    private Queue<string> receiveQueue = new Queue<string>();

    //用于收消息的容器
    private byte[] receiveBytes = new byte[1024];
    //返回收到的字节数
    private int receiveNum;

    //是否连接
    private bool isConnected = false;

    private void Awake()
    {
        instance = this;
        //防止切换场景网络连接就断了
        DontDestroyOnLoad(this.gameObject);
    }

    private void Update()
    {
        //如果线程里面有消息,就进行输出
        if (receiveQueue.Count > 0)
        {
            print(receiveQueue.Dequeue());
        }
    }

    public void Connect(string ip,int port)
    {
        //如果是连接状态 直接返回
        if (isConnected)
            return;

        if (socket == null)
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        //连接服务器
        IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse(ip), port);

        try
        {
            socket.Connect(ipPoint);
            isConnected = true;

            //开启发送线程
            ThreadPool.QueueUserWorkItem(SendMsg);
            //开启接受线程
            ThreadPool.QueueUserWorkItem(ReceiveMsg);
        }catch(SocketException e)
        {
            if (e.ErrorCode == 10061)
                print("服务器拒绝连接");
            else
                print("连接失败" + e.ErrorCode + e.Message);
        }
    }

    //发送消息
    public void Send(string info)
    {
        sendMsgQueue.Enqueue(info);
    }

    private void SendMsg(object obj)
    {
        while (isConnected)
        {
            if(sendMsgQueue.Count > 0)
            {
                socket.Send(Encoding.UTF8.GetBytes(sendMsgQueue.Dequeue()));
            }
        }
    }

    //不停的接受消息
    private void ReceiveMsg(object obj)
    {
        while (isConnected)
        {
            if (socket.Available > 0)
            {
                receiveNum = socket.Receive(receiveBytes);
                //收到消息 解析消息为字符串 并放入公共容器
                receiveQueue.Enqueue(Encoding.UTF8.GetString(receiveBytes, 0, receiveNum));
            }
        }
    }

    public void Close()
    {
        if(socket != null)
        {
            socket.Shutdown(SocketShutdown.Both);
            socket.Close();

            isConnected = false;
        }
    }

    private void OnDestroy()
    {
        Close();
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Main : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        if(NetMgr.Instance == null)
        {
            GameObject obj = new GameObject("Net");
            obj.AddComponent<NetMgr>();
        }

        NetMgr.Instance.Connect("127.0.0.1", 8080);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Lesson7 : MonoBehaviour
{
    public Button btn;
    public InputField input;

    // Start is called before the first frame update
    void Start()
    {
        btn.onClick.AddListener(() =>
        {
            if (input.text != "")
                NetMgr.Instance.Send(input.text);
        });
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Unity中实现本地客户端服务端之间发送图片,可以使用Unity自带的网络库UNET。具体步骤如下: 1. 创建一个空的Unity项目,然后在Unity编辑器中选择“Assets”->“Import Package”->“Custom Package”,导入UNET网络库。 2. 创建一个新的场景,并在场景中创建一个空对象,命名为“NetworkManager”。 3. 在“NetworkManager”对象上添加“NetworkManager”组件,并设置“Network Address”为“LocalHost”(表示连接到本地服务器)。 4. 在“NetworkManager”对象上添加“NetworkManagerHUD”组件,这将允许你在游戏运行时连接到本地服务器,并显示连接状态。 5. 在场景中创建一个新的空对象,命名为“MyNetworkManager”。 6. 在“MyNetworkManager”对象上添加以下脚本: ```csharp using UnityEngine; using UnityEngine.Networking; public class MyNetworkManager : NetworkManager { public void SendImage(byte[] data) { // 创建一个网络消息对象,用于发送图片数据 ImageMessage msg = new ImageMessage(); msg.imageData = data; // 向所有客户端发送消息 NetworkServer.SendToAll(MsgType.Custom, msg); } } // 自定义网络消息类型,用于发送图片数据 public class ImageMessage : MessageBase { public byte[] imageData; } ``` 7. 在场景中创建一个新的空对象,命名为“ImageSender”。 8. 在“ImageSender”对象上添加以下脚本: ```csharp using UnityEngine; using UnityEngine.UI; using UnityEngine.Networking; using System.IO; public class ImageSender : MonoBehaviour { public MyNetworkManager networkManager; public RawImage image; public Button sendButton; // Start is called before the first frame update void Start() { sendButton.onClick.AddListener(OnSendButtonClick); } // 发送按钮点击事件 void OnSendButtonClick() { // 将RawImage中的图片数据转换为PNG格式 Texture2D tex = (Texture2D)image.texture; byte[] data = tex.EncodeToPNG(); // 调用网络管理器发送图片数据 networkManager.SendImage(data); } } ``` 9. 在场景中创建一个新的空对象,命名为“ImageReceiver”。 10. 在“ImageReceiver”对象上添加以下脚本: ```csharp using UnityEngine; using UnityEngine.UI; using UnityEngine.Networking; using System.IO; public class ImageReceiver : NetworkBehaviour { public RawImage image; // 启动时注册网络消息类型 void Start() { NetworkManager.singleton.client.RegisterHandler(MsgType.Custom, OnReceiveImage); } // 接收到图片数据后的处理函数 void OnReceiveImage(NetworkMessage netMsg) { // 解析网络消息,获取图片数据 ImageMessage msg = netMsg.ReadMessage<ImageMessage>(); byte[] data = msg.imageData; // 创建Texture2D对象,并从数据中加载图片 Texture2D tex = new Texture2D(1, 1); tex.LoadImage(data); // 将图片显示在RawImage组件中 image.texture = tex; } } ``` 现在你已经完成了客户端服务端的代码编写。在场景中添加一个RawImage组件,用于显示图片。然后将“ImageSender”和“ImageReceiver”对象拖到场景中,并将“NetworkManager”对象拖到“ImageSender”的“networkManager”属性中。 运行游戏,并点击“ImageSender”对象上的“sendButton”按钮,你将看到RawImage组件中显示了发送的图片。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值