UDP通信
Unity-UDP通信
UDP(User Data Protocol,用户数据报协议)
(1) UDP是一个非连接的协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
(2) 由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。
(3) UDP信息包的标题很短,只有8个字节,相对于TCP的20个字节信息包的额外开销很小。
(4) 吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。
(5)UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的链接状态表(这里面有许多参数)。
(6)UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。
TCP与UDP的区别:
1.基于连接与无连接;
2.对系统资源的要求(TCP较多,UDP少);
3.UDP程序结构较简单;
4.流模式与数据报模式 ;
5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。
废话不多说,请看demo。
Server:
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 udpServer
{
class Program
{
public static byte[] buffer;
public static Socket server;
public static EndPoint clientEP;
static void Main(string[] args)
{
server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10086);
//服务端需要绑定ip
server.Bind(endPoint);
//其实无需初始化,ReceiveFrom后会由ref赋值,但是该api不允许传空对象
clientEP = (EndPoint)endPoint;
Console.WriteLine("开启服务器!");
//开启一个线程连接,必须的,否则主线程卡死
Thread Thread = new Thread(new ThreadStart(SocketReceive));
Thread.Start();
}
private static void SocketReceive()
{
//进入接收循环
while (true)
{
//对data清零
buffer = new byte[1024];
//获取客户端,获取客户端数据,用引用给客户端赋值
int recvLen = server.ReceiveFrom(buffer, ref clientEP);
Console.WriteLine("message from: " + clientEP.ToString()); //打印客户端信息
//输出接收到的数据
string recvStr = UTF8Encoding.UTF8.GetString(buffer, 0, recvLen);
Console.WriteLine("我是服务器,接收到客户端的数据" + recvStr);
//将接收到的数据经过处理再发送出去
string sendStr = "From Server: " + recvStr;
SocketSend(sendStr);
}
}
static void SocketSend(string sendStr)
{
//清空发送缓存
byte[] sendData = new byte[1024];
//数据类型转换
sendData = UTF8Encoding.UTF8.GetBytes(sendStr);
//发送给指定客户端
server.SendTo(sendData, sendData.Length, SocketFlags.None, clientEP);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
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 udpServer
{
class Program
{
public static byte[] buffer;
public static Socket server;
public static EndPoint clientEP;
static void Main(string[] args)
{
server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10086);
//服务端需要绑定ip
server.Bind(endPoint);
//其实无需初始化,ReceiveFrom后会由ref赋值,但是该api不允许传空对象
clientEP = (EndPoint)endPoint;
Console.WriteLine("开启服务器!");
//开启一个线程连接,必须的,否则主线程卡死
Thread Thread = new Thread(new ThreadStart(SocketReceive));
Thread.Start();
}
private static void SocketReceive()
{
//进入接收循环
while (true)
{
//对data清零
buffer = new byte[1024];
//获取客户端,获取客户端数据,用引用给客户端赋值
int recvLen = server.ReceiveFrom(buffer, ref clientEP);
Console.WriteLine("message from: " + clientEP.ToString()); //打印客户端信息
//输出接收到的数据
string recvStr = UTF8Encoding.UTF8.GetString(buffer, 0, recvLen);
Console.WriteLine("我是服务器,接收到客户端的数据" + recvStr);
//将接收到的数据经过处理再发送出去
string sendStr = "From Server: " + recvStr;
SocketSend(sendStr);
}
}
static void SocketSend(string sendStr)
{
//清空发送缓存
byte[] sendData = new byte[1024];
//数据类型转换
sendData = UTF8Encoding.UTF8.GetBytes(sendStr);
//发送给指定客户端
server.SendTo(sendData, sendData.Length, SocketFlags.None, clientEP);
}
}
}
|
Client:
using UnityEngine;
using System.Collections;
//引入库
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class Client : MonoBehaviour
{
//服务端终结点
IPEndPoint ipEnd;
//客户端socket
Socket socket;
//通过reveiveFrom函数,初始化的服务端终结点
EndPoint serverEnd;
// Use this for initialization
void Start()
{
InitSocket();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
SocketSend("hello world");
}
}
//初始化
void InitSocket()
{
//定义连接的服务器ip和端口,可以是本机ip,局域网,互联网
ipEnd = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10086);
//定义套接字类型,在主线程中定义
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//定义服务端endpoint
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
serverEnd = (EndPoint)sender;
print("waiting for sending UDP dgram");
//建立初始连接,这句非常重要,第一次连接初始化了serverEnd后面才能收到消息
SocketSend("hello world");
//开启一个线程连接,必须的,否则主线程卡死
Thread connectThread = new Thread(new ThreadStart(SocketReceive));
connectThread.Start();
}
void SocketSend(string sendStr)
{
//清空发送缓存
byte[] sendData = new byte[1024];
//数据类型转换
sendData = UTF8Encoding.UTF8.GetBytes(sendStr);
//发送给指定服务端
socket.SendTo(sendData, sendData.Length, SocketFlags.None, ipEnd);
}
//服务器接收
void SocketReceive()
{
//进入接收循环
while (true)
{
//对data清零
byte[] recvData = new byte[1024];
//获取客户端,获取服务端端数据,用引用给服务端赋值,实际上服务端已经定义好并不需要赋值
int recvLen = socket.ReceiveFrom(recvData, ref serverEnd);
print("message from: " + serverEnd.ToString()); //打印服务端信息
//输出接收到的数据
string recvStr = UTF8Encoding.UTF8.GetString(recvData, 0, recvLen);
print("我是客户端,接收到服务器的数据" + recvStr);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
using UnityEngine;
using System.Collections;
//引入库
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class Client : MonoBehaviour
{
//服务端终结点
IPEndPoint ipEnd;
//客户端socket
Socket socket;
//通过reveiveFrom函数,初始化的服务端终结点
EndPoint serverEnd;
// Use this for initialization
void Start()
{
InitSocket();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
SocketSend("hello world");
}
}
//初始化
void InitSocket()
{
//定义连接的服务器ip和端口,可以是本机ip,局域网,互联网
ipEnd = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10086);
//定义套接字类型,在主线程中定义
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//定义服务端endpoint
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
serverEnd = (EndPoint)sender;
print("waiting for sending UDP dgram");
//建立初始连接,这句非常重要,第一次连接初始化了serverEnd后面才能收到消息
SocketSend("hello world");
//开启一个线程连接,必须的,否则主线程卡死
Thread connectThread = new Thread(new ThreadStart(SocketReceive));
connectThread.Start();
}
void SocketSend(string sendStr)
{
//清空发送缓存
byte[] sendData = new byte[1024];
//数据类型转换
sendData = UTF8Encoding.UTF8.GetBytes(sendStr);
//发送给指定服务端
socket.SendTo(sendData, sendData.Length, SocketFlags.None, ipEnd);
}
//服务器接收
void SocketReceive()
{
//进入接收循环
while (true)
{
//对data清零
byte[] recvData = new byte[1024];
//获取客户端,获取服务端端数据,用引用给服务端赋值,实际上服务端已经定义好并不需要赋值
int recvLen = socket.ReceiveFrom(recvData, ref serverEnd);
print("message from: " + serverEnd.ToString()); //打印服务端信息
//输出接收到的数据
string recvStr = UTF8Encoding.UTF8.GetString(recvData, 0, recvLen);
print("我是客户端,接收到服务器的数据" + recvStr);
}
}
}
|
运行效果