Unity 使用Socket 简单实现通讯

unity 版本 2020.0.0a12
demo 下载
服务端代码

// ========================================================
// 描述:Unity 使用Soket 实现简单的聊天demo 
// 作者:qinglong 
// 创建时间:2020-04-07 11:31:27
// 版 本:1.0
// ========================================================

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

/// <summary>
/// 服务端代码只能有一个
/// </summary>
public class MySocketServer : MonoBehaviour
{
    
    Socket server;
    List<Socket> clients = new List<Socket>();
    byte[] buffer = new byte[1024];
    /// <summary>
    /// 创建服务器
    /// </summary>
    void Awake()
    {
        //ipv4 流式传输 tcp协议
        server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 54188);
        // 绑定终端
        server.Bind(endPoint);
        //开启监听 同一时间处理10个客户端连接
        server.Listen(10);
        //开启异步监听
        server.BeginAccept(ReceiveClient,server);
        Debug.Log("Server OK");
    }
    /// <summary>
    /// 异步获取客户端
    /// </summary>
    /// <param name="_result"></param>
    void ReceiveClient(IAsyncResult _result)
    {
        //获取服务器对象
        Socket server = _result.AsyncState as Socket;
        //获取客户端对象
        Socket client=server.EndAccept(_result);
        //再次开启异步监听
        server.BeginAccept(ReceiveClient, server);
        
        clients.Add(client);
       
        //异步接收信息
        client.BeginReceive(buffer,0,buffer.Length,SocketFlags.None, AsyncReceive,client);
    }

    /// <summary>
    /// 异步接收消息
    /// </summary>
    /// <param name="result"></param>
    void AsyncReceive(IAsyncResult result) {
        Socket client = result.AsyncState as Socket;
        //判断客户端是否断开连接 不判断 当一个客户端退出 Sever 异步会进入死循环 断电等异常退出无效
        if ((client.Poll(1000, SelectMode.SelectRead) && (client.Available == 0)) || !client.Connected)
        {
            clients.Remove(client);
            client.EndReceive(result);
            Debug.Log("服务器检测到 关闭客户端");
            return;
        }
        //检测当前只有一个客户端 提示当前客户端 对方没有上线
        if (clients.Count < 2)
        {
            clients[0].Send(System.Text.Encoding.UTF8.GetBytes("对方没有上线"));
            client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, AsyncReceive, client);
            return;
        }
        
        //关闭当前异步
        int len= client.EndReceive(result);
        //再次异步接收信息
        client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, AsyncReceive, client);
        
        //消息的解析
        byte[] buf = new byte[len];
        Buffer.BlockCopy(buffer, 0, buf, 0, len);
        string msg = System.Text.Encoding.UTF8.GetString(buf);
        sendMassage(System.Text.Encoding.UTF8.GetBytes("对方ID:" + msg), client);
        Debug.Log("对方ID"+msg);
    }
    /// <summary>
    /// 向客户端发送消息
    /// </summary>
    /// <param name="buf"></param>
    /// <param name="client"></param>
    void sendMassage(byte[] buf, Socket client)
    {
        //对发送消息的客户端 服务器不再将消息再次分发到信息
        for (int i = 0; i < clients.Count; i++)
        {
            if (clients[i]!=client)
            {
                clients[i].Send(buf);
            }
        }
        
    }
}

客户端代码

// ========================================================
// 描述:Unity 使用Soket 实现简单的聊天demo 
// 作者:qinglong 
// 创建时间:2020-04-07 11:31:27
// 版 本:1.0
// ========================================================

using System.Net.Sockets;
using System.Net;
using UnityEngine;
using UnityEngine.UI;
using System;

/// <summary>
/// 客户端可以存在多个
/// </summary>
public class MySocketClient : MonoBehaviour
{
    public Text Lefttext;
    public Text RightText;
    public ScrollRect SV;
    public InputField InputField;
    public Button Button;
    Socket client;
    byte[] buffer = new byte[1024];
    int Counts = 0;
    string massage;
    bool createUI = false;
    void Start()
    {
        //创建客户端
        StartConnect();

        //点击发送按钮 获取UI 输入信息 
        Button.onClick.AddListener(() => {
            GetUImassage((msg) =>
            {
                //将UI 信息发送到服务器
                sendMassage(msg);
            });
        });

    }

    /// <summary>
    /// 创建服务器
    /// </summary>
    void StartConnect()
    {
        client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //客户端连接客户端
        client.Connect(IPAddress.Parse("127.0.0.1"), 54188);
        Debug.Log(client.Connected);
        //异步接收信息
        client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, AsyncReceive, client);
    }

    /// <summary>
    /// 向服务器发送消息
    /// </summary>
    /// <param name="msg"></param>
    void sendMassage(string msg)
    {
        byte[] buffer = System.Text.Encoding.UTF8.GetBytes(msg);
        client.Send(buffer);
    }
    /// <summary>
    /// 获取UI 数据
    /// </summary>
    /// <param name="callback"></param>
    void GetUImassage(Action<string> callback)
    {
        Counts++;
        string[] id = client.LocalEndPoint.ToString().Split(':');
        string str = id[1] + "           " + InputField.text;
        Text rightText = Instantiate(RightText);
        rightText.transform.SetParent(SV.content);
        SV.content.sizeDelta = new Vector2(0, rightText.rectTransform.rect.height * Counts);
        SVtoLOW();
        rightText.text = "自己ID" + str;
        if (callback != null) callback(str);

    }
    /// <summary>
    /// 异步接收消息
    /// </summary>
    /// <param name="result"></param>
    void AsyncReceive(IAsyncResult result)
    {
        Socket client = result.AsyncState as Socket;
        int len = client.EndReceive(result);
        //再次异步接收信息
        client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, AsyncReceive, client);

        //消息的解析
        byte[] buf = new byte[len];
        Buffer.BlockCopy(buffer, 0, buf, 0, len);
        string msg = System.Text.Encoding.UTF8.GetString(buf);
        Debug.Log("Client     " + msg);
        Counts++;
        massage = msg;
        createUI = true;
    }

    /// <summary>
    /// 由于异步不能调用主线程 我是这么解决的
    /// </summary>
    private void Update()
    {
        if (createUI)
        {
            Text lefttext = Instantiate(Lefttext);
            lefttext.transform.SetParent(SV.content);
            SV.content.sizeDelta = new Vector2(0, lefttext.rectTransform.rect.height * Counts);
            SVtoLOW();
            string[] mag = massage.Split(':');
          
            lefttext.text = mag.Length > 0? massage : "对方ID:" + massage;
            
            
            createUI = false;
        }
    }

    //设置Scroll View滑动 到最下部
    void SVtoLOW()
    {
        float hight = SV.GetComponent<RectTransform>().rect.height;
        if (SV.content.rect.height > hight)
        {
            float top = SV.content.rect.height - hight;
            SV.content.localPosition = new Vector2(0, top);
        }
    }
    /// <summary>
    /// 关闭客户端 通知服务器 断电等异常退出无效
    /// </summary>
    private void OnDestroy()
    {
        client.Close();
        Debug.Log("客户端退出");
    }
}

在gethub 上找到这个脚本 UnityMainThreadDispatcher 他可以在异步中调用主线程创建text文本 等操作
下载链接下载地址
服务端没有变化
客户端代码

using System.Net.Sockets;
using System.Net;
using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;

/// <summary>
/// 客户端可以存在多个
/// </summary>
public class MySocketClient : MonoBehaviour
{
    public Text Lefttext;
    public Text RightText;
    public ScrollRect SV;
    public InputField InputField;
    public Button Button;
    Socket client;
    byte[] buffer = new byte[1024];
    int Counts = 0;
    void Start()
    {
        //创建客户端
        StartConnect();

        //点击发送按钮 获取UI 输入信息 
        Button.onClick.AddListener(() => {
            GetUImassage((msg) =>
            {
                //将UI 信息发送到服务器
                sendMassage(msg);
            });
        });

    }

    /// <summary>
    /// 创建服务器
    /// </summary>
    void StartConnect()
    {
        client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //客户端连接客户端
        client.Connect(IPAddress.Parse("127.0.0.1"), 54188);
        Debug.Log(client.Connected);
        //异步接收信息
        client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, AsyncReceive, client);
    }

    /// <summary>
    /// 向服务器发送消息
    /// </summary>
    /// <param name="msg"></param>
    void sendMassage(string msg)
    {
        byte[] buffer = System.Text.Encoding.UTF8.GetBytes(msg);
        client.Send(buffer);
    }
    /// <summary>
    /// 获取UI 数据
    /// </summary>
    /// <param name="callback"></param>
    void GetUImassage(Action<string> callback)
    {
        Counts++;
        string[] id = client.LocalEndPoint.ToString().Split(':');
        string str = id[1] + "           " + InputField.text;
        Text rightText = Instantiate(RightText);
        rightText.transform.SetParent(SV.content);
        SV.content.sizeDelta = new Vector2(0, rightText.rectTransform.rect.height * Counts);
        SVtoLOW();
        rightText.text = "自己ID" + str;
        if (callback != null) callback(str);

    }
    /// <summary>
    /// 异步接收消息
    /// </summary>
    /// <param name="result"></param>
    void AsyncReceive(IAsyncResult result)
    {
        Socket client = result.AsyncState as Socket;
        int len = client.EndReceive(result);
        //再次异步接收信息
        client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, AsyncReceive, client);

        //消息的解析
        byte[] buf = new byte[len];
        Buffer.BlockCopy(buffer, 0, buf, 0, len);
        string msg = System.Text.Encoding.UTF8.GetString(buf);
        Debug.Log("Client     " + msg);
        Counts++;
        UnityMainThreadDispatcher.Instance().Enqueue(CreateUI(msg));
    }

   
    IEnumerator CreateUI(string msg) {

        Text lefttext = Instantiate(Lefttext);
        lefttext.transform.SetParent(SV.content);
        SV.content.sizeDelta = new Vector2(0, lefttext.rectTransform.rect.height * Counts);
        SVtoLOW();
        string[] mag = msg.Split(':');

        lefttext.text = mag.Length > 0 ? msg : "对方ID:" + msg;
        yield return null;
    }
    //设置Scroll View滑动 到最下部
    void SVtoLOW()
    {
        float hight = SV.GetComponent<RectTransform>().rect.height;
        if (SV.content.rect.height > hight)
        {
            float top = SV.content.rect.height - hight;
            SV.content.localPosition = new Vector2(0, top);
        }
    }
    private void OnDestroy()
    {
        client.Close();
        Debug.Log("客户端退出");
    }
}

新的 客户端下载地址 下载地址

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity使用socket可以通过引入socket模块来实现。首先需要构造一个socket对象,可以使用socket.socket()方法来创建。该方法需要传入两个参数,分别是socket.AF_INET和socket.SOCK_STREAM,分别表示使用IPv4地址和流式Socket。\[1\] 在Unity中常用到的Socket方法包括: - IPAddress类:包含了一个IP地址 - IPEndPoint类:包含了一对IP地址和端口号 - Socket类的方法: - 创建一个Socket对象:Socket() - 绑定一个本地的IP和端口号:Bind() - 让Socket侦听传入的连接尝试,并指定侦听队列容量:Listen() - 初始化与另一个Socket的连接:Connect() - 接收连接并返回一个新的socket:Accept() - 输出数据到Socket:Send() - 从Socket中读取数据:Receive() - 关闭Socket(销毁连接):Close()\[2\] 需要注意的是,至少要定义一个要连接的远程主机的IP和端口号。端口号必须在1和65535之间,最好在1024以后。要连接的远程主机必须正在监听指定端口,也就是说你无法随意连接远程主机。一个Socket一次只能连接一台主机。Socket关闭后无法再次使用,每个Socket对象只能连接一台远程主机。如果你想连接到多台远程主机,你必须创建多个Socket对象。\[2\] 另外,需要注意的是,在Unity 5.1 ~ Unity2018中可以使用UNet(Unity Networking),但在Unity 2019之后,UNet已经被废弃,Mirror成为了替代UNet的解决方案。因此,不建议再使用UNet进行网络通信。\[3\] #### 引用[.reference_title] - *1* *3* [【游戏开发实战】Unity使用Socket通信实现简单的多人聊天室(万字详解 | 网络 | TCP | 通信 | Mirror | ...](https://blog.csdn.net/linxinfa/article/details/118888064)[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^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [UnitySocket网络编程](https://blog.csdn.net/weixin_45348216/article/details/128084313)[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^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值