【Unity程序】和【控制台程序】连接【asp.net core的websocket服务】(1)——在编辑器中运行

一、说明

1、本文实验内容所涉及的开发环境说明:

  • win11
  • VisualStudio2022(.Net6.0)
  • Unity2021.3.40

2、本文参考资料

【1】NativeWebSocketUnity包:
https://github.com/endel/NativeWebSocket
【2】asp.net core架设websocket国外小哥案例:
https://medium.com/bina-nusantara-it-division/implementing-websocket-client-and-server-on-asp-net-core-6-0-c-4fbda11dbceb
【3】感谢自动纺织机:ChatGPT/Claude

二、本文要实现的测试内容

在这里插入图片描述

  • 1、实现一个ASP.NET CORE服务端,它上面跑着一个websocket服务
  • 2、在【控制台应用程序】中与服务器websocket通信
  • 3、在【Unity程序】中与服务器websocket通信

三、测试效果截图

1、服务端截图

有一个用户连入时,显示简单信息
在这里插入图片描述

2、控制台应用程序截图

连接成功后,提示。
服务器一旦有用户连入,广播用户信息,广播总用户数
在这里插入图片描述

3、Unity程序截图

连接成功后,提示。
服务器一旦有用户连入,广播用户信息,广播总用户数
在这里插入图片描述

四、服务端创建

1、打开vs2022 -> 【创建新项目】

在这里插入图片描述

2、选择【ASP.NET CORE 空】项目模版

在这里插入图片描述

3、配置新项目

在这里插入图片描述
设置完毕点击【下一步】

4、 其他信息

譬如设置框架
在这里插入图片描述
设置完毕,点击【创建】

5、编写服务端逻辑

在这里插入图片描述
服务端代码

using System.Diagnostics;
using System.Net;
using System.Net.WebSockets;
using System.Text;

var builder = WebApplication.CreateBuilder(args); //
var connections = new List<WebSocket>();   //连接对象列表
										   //builder.WebHost.UseUrls("http://localhost:6969");
builder.WebHost.UseUrls("http://192.168.0.173:6969");

var app = builder.Build();                 //构建web应用程序实例
app.UseWebSockets();                       //启用websocket支持

app.Map("/ws", async context =>            //app.Map() 把某类网络请求与某个处理函数关联起来:当用户请求的是【/ws】时,服务器响应后面的兰姆达方法
{
	/**************************
	 每个ws连接请求发生的时候,服务器都会调用该处理流程 
	 这是一个并发流程,每一个ws请求都会经过它的处理
	 **************************/
	if (context.WebSockets.IsWebSocketRequest)
	{
		var curName = context.Request.Query["id"];//有用户连入
		var id = context.Connection.Id;
		var ip = context.Connection.RemoteIpAddress;
		Debug.WriteLine($"有用户连入:用户名为[{curName}]【Id= [{context.Connection.Id}] ip = [{context.Connection.RemoteIpAddress}]】");

		using var ws = await context.WebSockets.AcceptWebSocketAsync();
		connections.Add(ws);                      //添加连接的用户

		//广播信息
		await Broadcast($"有用户连入:id = [{id}],ip = [{ip}]");
		await Broadcast($"当前连接数量:{connections.Count}");
		await ReceiveMessage(ws,
			async (result, buffer) =>
			{
				if (result.MessageType == WebSocketMessageType.Text) //UTF8 文本信息
				{
					string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
					await Broadcast(ip + ":" + message);
				}
				else if (result.MessageType == WebSocketMessageType.Close || ws.State == WebSocketState.Aborted) //连接关闭
				{
					connections.Remove(ws);
					await Broadcast($"{ip}-{id}用户掉线了");
					await Broadcast($"当前用户连接数为{connections.Count}");
					await ws.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
				}
			});
	}
	else
	{
		context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
	}
});
await app.RunAsync();


//接收消息
async Task ReceiveMessage(WebSocket socket, Action<WebSocketReceiveResult, byte[]> handleMessage)
{
	var buffer = new byte[4096];
	while (socket.State == WebSocketState.Open)
	{
		var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
		handleMessage(result, buffer);
	}
}

//广播消息
async Task Broadcast(string message)
{
	var bytes = Encoding.UTF8.GetBytes(message);
	foreach (var socket in connections)
	{
		if (socket.State == WebSocketState.Open)
		{
			var arraySegment = new ArraySegment<byte>(bytes, 0, bytes.Length);
			await socket.SendAsync(arraySegment, WebSocketMessageType.Text, true, CancellationToken.None);
		}
	}
}

五、控制台客户端创建

1、创建新项目

在这里插入图片描述

2、选择【C#控制台应用】

在这里插入图片描述

3、配置新项目

在这里插入图片描述

4、设置.NET框架

在这里插入图片描述

5、编辑客户端逻辑

在这里插入图片描述
完整代码

// See https://aka.ms/new-console-template for more information

using System.Net.WebSockets;
using System.Text;

string name;
while (true)
{
	Console.Write("请输入名字:");
	name = Console.ReadLine();
	break;
}


var ws = new ClientWebSocket();

Console.WriteLine("开始连接服务器!");
//await ws.ConnectAsync(new Uri("ws://localhost:6969/ws"),CancellationToken.None);
await ws.ConnectAsync(new Uri("ws://192.168.0.173:6969/ws"), CancellationToken.None);

Console.WriteLine("连接成功!");

var receiveTask = Task.Run(async () => 
{
	var buffer = new byte[1024];
    while (true)
	{
		var result = await ws.ReceiveAsync(new ArraySegment<byte>(buffer),CancellationToken.None);
		if(result.MessageType == WebSocketMessageType.Close) 
		{  
			break; 
		}
		
		var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
		Console.WriteLine("收到信息:" + message);
	}
});

var sendTask = Task.Run(async () => 
{
	while (true)
	{
		var message =Console.ReadLine();
		if(message == "exit")
		{
			break;
		}

		var bytes = Encoding.UTF8.GetBytes(message);
		await ws.SendAsync(new ArraySegment<byte>(bytes),WebSocketMessageType.Text,true,CancellationToken.None);
	}
});

//发送或接收
await Task.WhenAny(receiveTask, sendTask);
if (ws.State == WebSocketState.Closed)
{
	await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
}

//发送和接收
await Task.WhenAll(receiveTask, sendTask);

六、Unity客户端创建

1、UI设计

在这里插入图片描述

2、层级关系

在这里插入图片描述

3、行为脚本清单

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.UI;
using NativeWebSocket;
using System;
using Cysharp.Threading.Tasks;

public class ConnectTest : MonoBehaviour
{
    /// <summary>
    /// IP地址
    /// </summary>
    public TMP_InputField ipf_ip;
    
    /// <summary>
    /// 端口号
    /// </summary>
    public TMP_InputField ipf_port;

    /// <summary>
    /// 连接服务器btn
    /// </summary>
    public Button btn_connect;

    /// <summary>
    /// 提示信息
    /// </summary>
    public TMP_Text text_info;

	private WebSocket websocket;

    // Start is called before the first frame update
    void Start()
    {
        //连接服务器-按钮-逻辑
        btn_connect.onClick.AddListener(async () =>
        {
            var ip = ipf_ip.text;
            var port = ipf_port.text;			

			try
			{
				websocket = new WebSocket($"ws://{ip}:{port}/ws");
				Debug.Log($"开始连接服务——ws://{ip}:{port}/ws");
				text_info.text += $"\n 开始连接服务——ws://{ip}:{port}/ws  \n";

				//连接打开时...
				websocket.OnOpen += () =>
				{
					text_info.text += "连上服务器\n";
				};

				//连接出错时...
				websocket.OnError += (e) =>
				{
					text_info.text += $"连接出错:{e}\n";
				};

				//连接关闭时...
				websocket.OnClose += (e) =>
				{
					text_info.text += $"连接关闭:{e}\n";
				};

				//收到二进制数据时...
				websocket.OnMessage += (bytes) =>
				{
					var message = System.Text.Encoding.UTF8.GetString(bytes);					
					text_info.text += $"收到消息: {message} \n";
				};

				//开始连接
				await websocket.Connect();				
			}
			catch (Exception e)
			{
				Debug.Log($"连接服务器出错:{e.Message}");
				text_info.text = $"连接服务器出错:{e.Message}";				
			}
		});
	}

	void Update()
	{
#if !UNITY_WEBGL || UNITY_EDITOR
		websocket.DispatchMessageQueue();
#endif
	}

}

至此,全部菜上齐!
后面会进行ASP.NET CORE 、websocket原理、应用和代码的讲解

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值