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

news2024/11/17 2:37:59

一、说明

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原理、应用和代码的讲解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1991713.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【安卓】SharedPreferences存储

SharedPreferences使用键值对的方式来存储数据的。也就是说&#xff0c;当保存一条数据的时候&#xff0c;需要给这条数据提供一个对应的键&#xff0c;这样在读取数据的时候就可以通过这个键把相应的值取出来。而且SharedPreferences还支持多种不同的数据类型存储&#xff0c;…

游戏原画可节省60-80%工时,大厂在用AI做什么

AIGC技术的迭代&#xff0c;是不是太快了点&#xff1f; 前年年中还是光速出图的Stable Diffusion&#xff0c;到年底就有了可以媲美真人的文本处理模型ChatGPT&#xff0c;今年开年又蹦出来了可以凭空变出视频、动画的Sora……我们对技术升级的认知被一次次刷新&#xff0c;同…

BHGMall生活超市天通苑店盛大开业,多重好礼只等你来

据悉8月10日&#xff0c;BHGMall生活超市天通苑店焕新开业&#xff0c;催旺“七夕浪漫经济”造福社区百姓&#xff0c;不仅提供助老服务&#xff0c;还有超值福利、多重好礼&#xff0c;倡导天天有低价&#xff0c;以实惠的价格买到优质的商品&#xff0c;提升居民幸福感和城市…

解题思考:为什么Java中使用Arrays.stream()创建流处理数组通常会增加开销,提高时间复杂度?

目录 问题描述&#xff1a;问题回答&#xff1a; 问题描述&#xff1a; 在解决力扣上的&#xff1a; 3131. 找出与数组相加的整数 I 时&#xff0c;使用传统遍历会比创建流处理数组的时间复杂度更低。 1.传统遍历代码&#xff1a; class Solution {public int addedInteger(i…

大模型与数据分析的融合:创新与发展的新机遇

大模型与数据分析的融合&#xff1a;创新与发展的新机遇 前言大模型与数据分析的融合 前言 大模型与数据分析的融合正成为推动企业发展的关键力量。大模型在数据分析领域展现出了强大的能力。它能够以接近人类的水平理解和处理自然语言&#xff0c;快速、准确地解析大量非结构…

vue实现PC端图片放大缩小可鼠标拖动,鼠标滚轮控制放大缩小完整代码付效果图

vue实现图片放大缩小可鼠标拖动&#xff0c;鼠标滚轮控制放大缩小完整代码付效果图 效果图&#xff1a; 创建一个ImageViewer 组件&#xff0c;并且在当前页面引用完整代码如下&#xff1a; 代码引用&#xff1a; <template><view><image-viewer :imageUrl&q…

大数据-69 Kafka 高级特性 物理存储 实机查看分析 日志存储一篇详解

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

SOMEIP_ETS_022:echoStaticUINT8Array_One_Dimensional

测试目的&#xff1a; 确保DUT能够正确处理一维静态UINT8数组参数&#xff0c;并且在发送和接收过程中保持参数值和顺序不变。 描述 本测试用例将验证DUT在处理包含一维静态UINT8数组参数的SOME/IP消息时&#xff0c;是否能够准确地发送和接收这些参数&#xff0c;确保返回的…

[数据结构] 万字解析排序算法

文章目录 快速排序双指针法整体排序过程整理选择基准值&#xff08;Pivot&#xff09;单趟划分&#xff08;Partitioning&#xff09;递归分治&#xff08;Divide and Conquer&#xff09;终止条件合并 整体代码实现为什么相遇位置一定是小值&#xff1f;情况 1: 右指针j找到了…

HexView 刷写文件脚本处理工具-基本功能介绍(七)-导出VBF/GM/GM-FBL

导出Ford VBF数据容器 VBF文件格式是Ford和Volvo Cars使用的多功能二进制格式。此文件的输出基于“Versatile Binary Format”规范,版本从2.2至2.5。在对话框中输入的所有值将被写入INI文件。INI文件也可以用于命令行选项,以在不需要用户输入的情况下生成输出。 导出GM数据…

网卡与Linux网络结构(中)

1 socket数据结构 socket源码 socket结构体是操作系统网络编程接口的一个核心组件。在操作系统中&#xff0c;socket结构体定义了一个网络连接的抽象&#xff0c;包括文件描述符、地址信息、连接状态等。 socket结构体代码位于<include/linux/net.h> struct socket { s…

android13 串口编号修改 串口名修改

总纲 android13 rom 开发总纲说明 目录 1.前言 2.技术分析 别名定义的语法规则 3.修改示例 使用别名 注意事项 4.不生效分析 5.编译查看 6.其他方法 7.彩蛋 1.前言 更改Android设备的串口编号涉及对系统深层次的配置进行修改,通常是为了解决硬件兼容性问题或满足特…

MySQL:约束

目录 1、约束 1.1 约束类型 2、非空约束 2.1 没有指定not null 2.2 指定not null 3、唯一约束 3.1 没有指定unique 3.2 指定unique 4、默认约束 5、主键约束 5.1 主键 5.2 主键自增类型 5.2.1 主键自增全列插入 5.2.2 主键自增指定列插入 5.3 复合主键 6、外键约…

探秘充电桩测试负载箱

随着电动汽车的普及&#xff0c;充电桩已经成为了城市中不可或缺的一部分。为了保证充电桩的质量和安全性&#xff0c;对其进行严格的测试是必不可少的。而在这个过程中&#xff0c;充电桩测试负载箱扮演着至关重要的角色。那么&#xff0c;什么是充电桩测试负载箱&#xff1f;…

【问题记录】Python中用yield实现打字机效果

用yield实现打字机效果 前言示例注意点 前言 在人工智能&#xff08;AI&#xff09;领域&#xff0c;yield 函数在处理大数据集和实现异步编程时非常重要。 异步编程是一种常见的编程模式&#xff0c;它可以提高程序的执行效率。yield 可以用于实现协程&#xff0c;使得程序在…

未来已来:人工智能如何重塑Facebook的用户体验?

在数字化时代的浪潮中&#xff0c;人工智能&#xff08;AI&#xff09;正成为推动技术进步和用户体验优化的核心力量。Facebook&#xff08;现Meta Platforms&#xff09;作为全球领先的社交媒体平台&#xff0c;正在充分利用人工智能技术&#xff0c;以重塑用户体验&#xff0…

文档翻译免费软件有哪些?不容错过的5个翻译利器

大学生暑期生活日常都丰富多彩&#xff0c;充满了挑战与收获。 他们不仅沉浸在外语学习的海洋中&#xff0c;努力提升语言能力&#xff0c;还深入钻研各类论文文献&#xff0c;积极探索学术的无限可能。然而&#xff0c;在这个过程中&#xff0c;不同语言的资料往往成为他们求…

spring boot3.x快速入门

下一篇&#xff1a;Spring Boot 3.x gradle脚手架工程build.gradle详解 本教程将基于gradle项目构建工具来快速构建一个spring boot 3.x的最简单的web应用&#xff0c;其中涉及各种构建技巧和细节&#xff0c;希望能帮到初学者~ 文章目录 先决条件JDK17gradle全局配置 gradle项…

RAPTOR模型在长文档知识检索中的应用

人工智能咨询培训老师叶梓 转载标明出处 传统的检索增强型语言模型&#xff08;RALMs&#xff09;在检索时往往只关注短且连续的文本块&#xff0c;这限制了它们对整体文档上下文的全面理解。例如&#xff0c;在需要整合文本多个部分知识的主题性问题上&#xff0c;如理解整本书…

哈佛大学单细胞课程|笔记汇总 (六)

哈佛大学单细胞课程|笔记汇总 &#xff08;五&#xff09; 哈佛大学单细胞课程|笔记汇总 &#xff08;四&#xff09; &#xff08;六&#xff09;Single-cell RNA-seq clustering analysis: aligning cells across conditions 我们的数据集包含来自两个不同条件&#xff08…