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
)
;
}
}
}
|
运行效果