UDP实现一个简易的聊天室 (Unity&&C#完成)
效果展示(尚未完善)

UDP
User Data Protocol 用户数据报协议
概述
UDP是不连接的数据报模式。即传输数据之前源端和终端不建立连接。使用尽最大努力交付原则,即不保证可靠交付。
数据报模式:由于不建立连接,收到的数据可能是任意主机发送的,所以接收端Read次数必须与发送端Write次数相同,每次只接收一个报文,避免多个报文合并。但如果报文过长,多出部分会被丢弃,所以注意数据最大为1472字节。
实现步骤
服务端 客户端
获取本机终结点 获取本机终结点
创建UdpClient对象 创建UdpClient对象
接收任意终结点消息 接收任意终结点消息
向客户端发送消息 向服务端发送消息
…… …
关闭连接 关闭连接
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Common;
using UIWidgetsSamples;
using System; /// <summary>
/// 服务端
/// </summary>
public class ChatUDPServerTest : MonoBehaviour
{
public string serverIP;
//IP地址
public int serverPort;
//端口
//1.创建Scoket对象 IP Port
private Thread thread;
private UdpClient udpSeivic;
public void Start()
{
chatView = transform.FindChildByName("ChatView").
GetComponent<ChatView>();
//给端口和IP
//构建终结点 IP和一个端口
IPEndPoint localEP = new
IPEndPoint(IPAddress.Parse(serverIP), serverPort);
udpSeivic = new UdpClient(localEP); thread = new Thread(ReceiveMessage);
thread.Start();
} /// <summary>
/// 接收消息
/// </summary>
private void ReceiveMessage()
{
while (true)
{
IPEndPoint remote = new
IPEndPoint(IPAddress.Any, );
//创建任意终结点
//ref
byte[] date = udpSeivic.Receive(ref remote);
//Receive接收消息 如果没有收到消息 线程阻塞 放在线程中
string msg = Encoding.UTF8.GetString(date);
//获取的客户都安信息
Debug.Log(remote.Address + "===" + remote.Port);
//如果接收客户端的消息,会把任意终结点修改为客户端的终结点
ThreadCrossHelper.Instance.ExecuteOnMainThread(() => { ShowMessage(msg); });
}
}
private ChatView chatView;
/// <summary>
/// 显示消息
/// </summary>
/// <param name="msg"></param>
public void ShowMessage(string msg)
{
chatView.DataSource.Add(new ChatLine()
{
UserName = "AnnnS",
Message = msg,
Time = DateTime.Now,
Type = ChatLineType.User,
});
}
private void OnApplicationQuit()
{
udpSeivic.Close();
thread.Abort();
}
}
ChatUDPServerTest
脚本引用的工具箱
- MonoSingleton (泛型单例)
- ThreadCrossHelper (为子线程提供,可以在主线程中执行的方法)
- TransformHelper(根据名称查找后代元素)
using System.Collections;
using System.Collections.Generic;
using UnityEngine; namespace Common
{
/// <summary>
///
/// </summary>
public class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
//public static T Instance
//{
// get;
// private set;
//}
//private void Awake()
//{
// Instance = this as T;
//}
//按需加载
private static T instance;
public static T Instance
{
get
{
if (instance == null)
{
//在场景中查找对象
instance = FindObjectOfType<T>();
if (instance == null)
{
//创建游戏对象 附加 脚本对象
new GameObject("Singleton of " + typeof(T)).AddComponent<T>();//立即执行Awake
}
else
{
instance.Initialized();
}
}
return instance;
}
} protected virtual void Initialized()
{ } [Tooltip("是否需要跨场景不销毁")]
public bool isDontDestroy = true; //如果管理类自行附加到物体中
//在Awake中为instance赋值
protected void Awake()
{
if (isDontDestroy)
{
DontDestroyOnLoad(gameObject);
}
if (instance == null)
{
instance = this as T;
instance.Initialized();
}
}
}
}
MonoSingleton
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine; namespace Common
{
/// <summary>
///
/// </summary>
public class ThreadCrossHelper : MonoSingleton<ThreadCrossHelper>
{
/// <summary>
/// 延迟项
/// </summary>
class DelayedItem
{
public Action CurrentAction { get; set; }
public DateTime Time { get; set; }
} private List<DelayedItem> actionList;
//private List<Action> actionList;
//private List<float> timeList; protected override void Initialized()
{
base.Initialized(); actionList = new List<DelayedItem>();
} private void Update()
{
for (int i = actionList.Count - ; i >= ; i--)
{
//到时间
if (actionList[i].Time <= DateTime.Now)
{
lock (actionList)
{
actionList[i].CurrentAction();//执行
actionList.RemoveAt(i);//从列表中移除
}
}
}
}
/// <summary>
/// 为子线程提供,可以在主线程中执行的方法
/// </summary>
/// <param name="action"></param>
/// <param name="dealy"></param>
public void ExecuteOnMainThread(Action action, float dealy = )
{
DelayedItem item = new DelayedItem()
{
CurrentAction = action,
//Time = Time.time + dealy
Time = DateTime.Now.AddSeconds(dealy)
};
lock (actionList)
{
actionList.Add(item);
}
}
}
}
ThreadCrossHelper
using System.Collections;
using System.Collections.Generic;
using UnityEngine; namespace Common
{
/// <summary>
/// 变换组件助手类
/// </summary>
public static class TransformHelper
{
/// <summary>
/// 未知层级,根据名称查找后代元素
/// </summary>
/// <param name="currentTF"></param>
/// <param name="childName"></param>
/// <returns></returns>
public static Transform FindChildByName(this Transform currentTF, string childName)
{
Transform childTF = currentTF.Find(childName);
if (childTF != null) return childTF;
//将问题推迟给子物体
for (int i = ; i < currentTF.childCount; i++)
{
//在方法体内部,又遇到了相同的问题,所以需要调用自身。
childTF = FindChildByName(currentTF.GetChild(i), childName);
if (childTF != null) return childTF;
}
return null;
}
}
}
TransformHelper
UDP实现一个简易的聊天室 (Unity&&C#完成)的更多相关文章
- C 基于UDP实现一个简易的聊天室
引言 本文是围绕Linux udp api 构建一个简易的多人聊天室.重点看思路,帮助我们加深 对udp开发中一些api了解.相对而言udp socket开发相比tcp socket开发注意的细节要少 ...
- TCP实现一个简易的聊天室 (Unity&&C#完成)
效果展示 TCP Transmission Control Protocol 传输控制协议 TCP是面向连接的流模式(俗称:网络流).即传输数据之前源端和终端建立可靠的连接,保证数据传输的正确性. 流 ...
- 与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室
原文:与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...
- 与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室
原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...
- [SignalR]一个简单的聊天室
原文:[SignalR]一个简单的聊天室 1.说明 开发环境:Microsoft Visual Studio 2010 以及需要安装NuGet. 2.添加SignalR所需要的类库以及脚本文件: 3. ...
- 用ServletContext做一个简单的聊天室
这里主要是ServletContext的一个特性:ServletContext是一个公共的空间,可以被所有的客户访问.由此可见ServletContext比cookie和session的作用范围要大[ ...
- 基于websocket实现的一个简单的聊天室
本文是基于websocket写的一个简单的聊天室的例子,可以实现简单的群聊和私聊.是基于websocket的注解方式编写的.(有一个小的缺陷,如果用户名是中文,会乱码,不知如何处理,如有人知道,请告知 ...
- [XMPP]简易的聊天室实现[二](使用CocoaAsyncSocket)
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- 利用JavaUDPSocket+多线程模拟实现一个简单的聊天室程序
对Socket的一点个人理解:Socket原意是指插座.家家户户都有五花八门的家用电器,但它们共用统一制式的插座.这样做的好处就是将所有家用电器的通电方式统一化,不需要大费周章地在墙壁上凿洞并专门接电 ...
随机推荐
- Python2操作中文名文件乱码解决方案
Python2默认是不支持中文的,一般我们在程序的开头加上#-*-coding:utf-8-*-来解决这个问题,但是在我用open()方法打开文件时,中文名字却显示成了乱码. 我先给大家说说Pytho ...
- springboot 2.0 自动装配原理 以redis为例
当面试管问你springboot 和 普通spring 有什么区别? 您还在回答: 简化了配置 ,内置tomcat 等等 吗 ? 那只是皮毛, 最重要的还是自动化配置.一起来了解一下 第一步: 第二步 ...
- 基于git的管理应用程序基线包和版本
由于工作的需要,身为git的小白的我开始研究git相关的命令和操作.结合网上收集和廖雪峰的git教程,记录所学知识点. 相关的效果就不再这里显示了. 首先我们看一下git的常用命令: 常用命令 git ...
- linux下mysql的安装配置
http://blog.csdn.net/xiagege3/article/details/41852895 (实战用的此文,要求mysql源码必须是未编译的,需依赖cmake编译) http:/ ...
- 关于document.cookie的使用
设置cookie每个cookie都是一个名/值对,可以把下面这样一个字符串赋值给document.cookie:document.cookie="userId=828";如果要一次 ...
- OpenLayers3 学习-1
OpenLayers3 学习-1-简介 OpenLayers3(OL3)对OL2进行了重新设计和实现,支持多种格式的商业和免费的地图数据源.未来的版本将包括显示3D地图或利用WebGL进行大规模矢量数 ...
- maven核心概念及约定的目录结构
- Shrio04 自定义Realm
1 说明 1.1 Realm的作用 Realm和认证和授权时的数据交互有关,相当于DAO层. 1.2 AuthorizingRealm >层次关系图 >作用继承AuthorizingRea ...
- day25 map,filter,reduce 内置函数,作业
=====================作业一#用map来处理字符串列表啊,把列表中所有人都变成sb,比方alex_sbname=['alex','wupeiqi','yuanhao']###### ...
- Linux mmap函数简介
一.简介 Linux提供了内存映射函数mmap, 它把文件内容映射到一段内存上(准确说是虚拟内存上), 通过对这段内存的读取和修改, 实现对文件的读取和修改, 先来看一下mmap的函数声明: 头文件: ...