- 浏览: 283553 次
- 性别:
- 来自: 济南
文章分类
最新评论
unity深入研究--开发之C#使用Socket与HTTP连接服务器传输数据包
1.Socket
Socket不要写在脚本上,如果写在脚本上游戏场景一旦切换,那么这条脚本会被释放掉,Socket会断开连接。场景切换完毕后需要重新在与服务器建立Socket连接,这样会很麻烦。所以我们需要把Socket写在一个单例的类中,不用继承MonoBehaviour。这个例子我模拟一下,主角在游戏中移动,时时向服务端发送当前坐标,当服务器返回同步坐标时角色开始同步服务端新角色坐标。
Socket在发送消息的时候采用的是字节数组,也就是说无论你的数据是 int float short object 都会将这些数据类型先转换成byte[] , 目前在处理发送的地方我使用的是数据包,也就是把(角色坐标)结构体object转换成byte[]发送, 这就牵扯一个问题, 如何把结构体转成字节数组, 如何把字节数组回转成结构体。请大家接续阅读,答案就在后面,哇咔咔。
直接上代码
JFSocket.cs 该单例类不要绑定在任何对象上
001 |
using
UnityEngine;
|
002 |
using
System.Collections;
|
003 |
using
System;
|
004 |
using
System.Threading;
|
005 |
using
System.Text;
|
006 |
using
System.Net;
|
007 |
using
System.Net.Sockets;
|
008 |
using
System.Collections.Generic;
|
009 |
using
System.IO;
|
010 |
using
System.Runtime.InteropServices;
|
011 |
using
System.Runtime.Serialization;
|
012 |
using
System.Runtime.Serialization.Formatters.Binary;
|
013 |
|
014 |
public
class JFSocket
|
015 |
{ |
016 |
|
017 |
//Socket客户端对象
|
018 |
private Socket clientSocket;
|
019 |
//JFPackage.WorldPackage是我封装的结构体,
|
020 |
//在与服务器交互的时候会传递这个结构体
|
021 |
//当客户端接到到服务器返回的数据包时,我把结构体add存在链表中。
|
022 |
public List<JFPackage.WorldPackage> worldpackage;
|
023 |
//单例模式
|
024 |
private static
JFSocket instance;
|
025 |
public static
JFSocket GetInstance()
|
026 |
{
|
027 |
if (instance ==
null )
|
028 |
{
|
029 |
instance = new
JFSocket();
|
030 |
}
|
031 |
return instance;
|
032 |
}
|
033 |
|
034 |
//单例的构造函数
|
035 |
JFSocket()
|
036 |
{
|
037 |
//创建Socket对象, 这里我的连接类型是TCP
|
038 |
clientSocket = new
Socket (AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
|
039 |
//服务器IP地址
|
040 |
IPAddress ipAddress = IPAddress.Parse ( "192.168.1.100" );
|
041 |
//服务器端口
|
042 |
IPEndPoint ipEndpoint = new
IPEndPoint (ipAddress, 10060);
|
043 |
//这是一个异步的建立连接,当连接建立成功时调用connectCallback方法
|
044 |
IAsyncResult result = clientSocket.BeginConnect (ipEndpoint, new AsyncCallback (connectCallback),clientSocket);
|
045 |
//这里做一个超时的监测,当连接超过5秒还没成功表示超时
|
046 |
bool success = result.AsyncWaitHandle.WaitOne( 5000,
true );
|
047 |
if ( !success )
|
048 |
{
|
049 |
//超时
|
050 |
Closed();
|
051 |
Debug.Log( "connect Time Out" );
|
052 |
} else
|
053 |
{
|
054 |
//与socket建立连接成功,开启线程接受服务端数据。
|
055 |
worldpackage = new
List<JFPackage.WorldPackage>();
|
056 |
Thread thread = new
Thread( new ThreadStart(ReceiveSorket));
|
057 |
thread.IsBackground = true ;
|
058 |
thread.Start();
|
059 |
}
|
060 |
}
|
061 |
|
062 |
private void
connectCallback(IAsyncResult asyncConnect)
|
063 |
{
|
064 |
Debug.Log( "connectSuccess" );
|
065 |
}
|
066 |
|
067 |
private void
ReceiveSorket()
|
068 |
{
|
069 |
//在这个线程中接受服务器返回的数据
|
070 |
while ( true )
|
071 |
{
|
072 |
|
073 |
if (!clientSocket.Connected)
|
074 |
{
|
075 |
//与服务器断开连接跳出循环
|
076 |
Debug.Log( "Failed to clientSocket server." );
|
077 |
clientSocket.Close();
|
078 |
break ;
|
079 |
}
|
080 |
try
|
081 |
{
|
082 |
//接受数据保存至bytes当中
|
083 |
byte [] bytes = new
byte [4096];
|
084 |
//Receive方法中会一直等待服务端回发消息
|
085 |
//如果没有回发会一直在这里等着。
|
086 |
int i = clientSocket.Receive(bytes);
|
087 |
if (i <= 0)
|
088 |
{
|
089 |
clientSocket.Close();
|
090 |
break ;
|
091 |
}
|
092 |
|
093 |
//这里条件可根据你的情况来判断。
|
094 |
//因为我目前的项目先要监测包头长度,
|
095 |
//我的包头长度是2,所以我这里有一个判断
|
096 |
if (bytes.Length > 2)
|
097 |
{
|
098 |
SplitPackage(bytes,0);
|
099 |
} else
|
100 |
{
|
101 |
Debug.Log( "length is not > 2" );
|
102 |
}
|
103 |
|
104 |
}
|
105 |
catch (Exception e)
|
106 |
{
|
107 |
Debug.Log( "Failed to clientSocket error." + e);
|
108 |
clientSocket.Close();
|
109 |
break ;
|
110 |
}
|
111 |
}
|
112 |
}
|
113 |
|
114 |
private void
SplitPackage( byte [] bytes , int
index)
|
115 |
{
|
116 |
//在这里进行拆包,因为一次返回的数据包的数量是不定的
|
117 |
//所以需要给数据包进行查分。
|
118 |
while ( true )
|
119 |
{
|
120 |
//包头是2个字节
|
121 |
byte [] head = new
byte [2];
|
122 |
int headLengthIndex = index + 2;
|
123 |
//把数据包的前两个字节拷贝出来
|
124 |
Array.Copy(bytes,index,head,0,2);
|
125 |
//计算包头的长度
|
126 |
short length = BitConverter.ToInt16(head,0);
|
127 |
//当包头的长度大于0 那么需要依次把相同长度的byte数组拷贝出来
|
128 |
if (length > 0)
|
129 |
{
|
130 |
byte [] data = new
byte [length];
|
131 |
//拷贝出这个包的全部字节数
|
132 |
Array.Copy(bytes,headLengthIndex,data,0,length);
|
133 |
//把数据包中的字节数组强制转换成数据包的结构体
|
134 |
//BytesToStruct()方法就是用来转换的
|
135 |
//这里需要和你们的服务端程序商量,
|
136 |
JFPackage.WorldPackage wp = new
JFPackage.WorldPackage();
|
137 |
wp = (JFPackage.WorldPackage)BytesToStruct(data,wp.GetType());
|
138 |
//把每个包的结构体对象添加至链表中。
|
139 |
worldpackage.Add(wp);
|
140 |
//将索引指向下一个包的包头
|
141 |
index = headLengthIndex + length;
|
142 |
|
143 |
} else
|
144 |
{
|
145 |
//如果包头为0表示没有包了,那么跳出循环
|
146 |
break ;
|
147 |
}
|
148 |
}
|
149 |
}
|
150 |
|
151 |
//向服务端发送一条字符串
|
152 |
//一般不会发送字符串 应该是发送数据包
|
153 |
public void
SendMessage( string str)
|
154 |
{
|
155 |
byte [] msg = Encoding.UTF8.GetBytes(str);
|
156 |
|
157 |
if (!clientSocket.Connected)
|
158 |
{
|
159 |
clientSocket.Close();
|
160 |
return ;
|
161 |
}
|
162 |
try
|
163 |
{
|
164 |
//int i = clientSocket.Send(msg);
|
165 |
IAsyncResult asyncSend = clientSocket.BeginSend (msg,0,msg.Length,SocketFlags.None, new AsyncCallback (sendCallback),clientSocket);
|
166 |
bool success = asyncSend.AsyncWaitHandle.WaitOne( 5000,
true );
|
167 |
if ( !success )
|
168 |
{
|
169 |
clientSocket.Close();
|
170 |
Debug.Log( "Failed to SendMessage server." );
|
171 |
}
|
172 |
}
|
173 |
catch
|
174 |
{
|
175 |
Debug.Log( "send message error" );
|
176 |
}
|
177 |
}
|
178 |
|
179 |
//向服务端发送数据包,也就是一个结构体对象
|
180 |
public void
SendMessage( object obj)
|
181 |
{
|
182 |
|
183 |
if (!clientSocket.Connected)
|
184 |
{
|
185 |
clientSocket.Close();
|
186 |
return ;
|
187 |
}
|
188 |
try
|
189 |
{
|
190 |
//先得到数据包的长度
|
191 |
short size = ( short )Marshal.SizeOf(obj);
|
192 |
//把数据包的长度写入byte数组中
|
193 |
byte [] head = BitConverter.GetBytes(size);
|
194 |
//把结构体对象转换成数据包,也就是字节数组
|
195 |
byte [] data = StructToBytes(obj);
|
196 |
|
197 |
//此时就有了两个字节数组,一个是标记数据包的长度字节数组, 一个是数据包字节数组,
|
198 |
//同时把这两个字节数组合并成一个字节数组
|
199 |
|
200 |
byte [] newByte = new
byte [head.Length + data.Length];
|
201 |
Array.Copy(head,0,newByte,0,head.Length);
|
202 |
Array.Copy(data,0,newByte,head.Length, data.Length);
|
203 |
|
204 |
//计算出新的字节数组的长度
|
205 |
int length = Marshal.SizeOf(size) + Marshal.SizeOf(obj);
|
206 |
|
207 |
//向服务端异步发送这个字节数组
|
208 |
IAsyncResult asyncSend = clientSocket.BeginSend (newByte,0,length,SocketFlags.None, new AsyncCallback (sendCallback),clientSocket);
|
209 |
//监测超时
|
210 |
bool success = asyncSend.AsyncWaitHandle.WaitOne( 5000,
true );
|
211 |
if ( !success )
|
212 |
{
|
213 |
clientSocket.Close();
|
214 |
Debug.Log( "Time Out !" );
|
215 |
}
|
216 |
|
217 |
}
|
218 |
catch (Exception e)
|
219 |
{
|
220 |
Debug.Log( "send message error: " + e );
|
221 |
}
|
222 |
}
|
223 |
|
224 |
//结构体转字节数组
|
225 |
public byte [] StructToBytes( object structObj)
|
226 |
{
|
227 |
|
228 |
int size = Marshal.SizeOf(structObj);
|
229 |
IntPtr buffer = Marshal.AllocHGlobal(size);
|
230 |
try
|
231 |
{
|
232 |
Marshal.StructureToPtr(structObj,buffer, false );
|
233 |
byte [] bytes = new
byte [size];
|
234 |
Marshal.Copy(buffer, bytes,0,size);
|
235 |
return bytes;
|
236 |
}
|
237 |
finally
|
238 |
{
|
239 |
Marshal.FreeHGlobal(buffer);
|
240 |
}
|
241 |
}
|
242 |
//字节数组转结构体
|
243 |
public object
BytesToStruct( byte [] bytes, Type strcutType)
|
244 |
{
|
245 |
int size = Marshal.SizeOf(strcutType);
|
246 |
IntPtr buffer = Marshal.AllocHGlobal(size);
|
247 |
try
|
248 |
{
|
249 |
Marshal.Copy(bytes,0,buffer,size);
|
250 |
return Marshal.PtrToStructure(buffer, strcutType);
|
251 |
}
|
252 |
finally
|
253 |
{
|
254 |
Marshal.FreeHGlobal(buffer);
|
255 |
}
|
256 |
|
257 |
}
|
258 |
|
259 |
private void
sendCallback (IAsyncResult asyncSend)
|
260 |
{
|
261 |
|
262 |
}
|
263 |
|
264 |
//关闭Socket
|
265 |
public void
Closed()
|
266 |
{
|
267 |
|
268 |
if (clientSocket != null
&& clientSocket.Connected)
|
269 |
{
|
270 |
clientSocket.Shutdown(SocketShutdown.Both);
|
271 |
clientSocket.Close();
|
272 |
}
|
273 |
clientSocket = null ;
|
274 |
}
|
275 |
|
276 |
} |
为了与服务端达成默契,判断数据包是否完成。我们需要在数据包中定义包头 ,包头一般是这个数据包的长度,也就是结构体对象的长度。正如代码中我们把两个数据类型 short 和 object 合并成一个新的字节数组。
然后是数据包结构体的定义,需要注意如果你在做IOS和Android的话数据包中不要包含数组,不然在结构体转换byte数组的时候会出错。
Marshal.StructureToPtr () error : Attempting to JIT compile method
JFPackage.cs
01 |
using
UnityEngine;
|
02 |
using
System.Collections;
|
03 |
using
System.Runtime.InteropServices;
|
04 |
|
05 |
public
class JFPackage
|
06 |
{ |
07 |
//结构体序列化
|
08 |
[System.Serializable]
|
09 |
//4字节对齐 iphone 和 android上可以1字节对齐
|
10 |
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
11 |
public struct
WorldPackage
|
12 |
{
|
13 |
public byte
mEquipID;
|
14 |
public byte
mAnimationID;
|
15 |
public byte
mHP;
|
16 |
public short
mPosx;
|
17 |
public short
mPosy;
|
18 |
public short
mPosz;
|
19 |
public short
mRosx;
|
20 |
public short
mRosy;
|
21 |
public short
mRosz;
|
22 |
|
23 |
public WorldPackage( short posx, short
posy, short
posz, short
rosx, short
rosy, short
rosz, byte equipID, byte animationID, byte hp)
|
24 |
{
|
25 |
mPosx = posx;
|
26 |
mPosy = posy;
|
27 |
mPosz = posz;
|
28 |
mRosx = rosx;
|
29 |
mRosy = rosy;
|
30 |
mRosz = rosz;
|
31 |
mEquipID = equipID;
|
32 |
mAnimationID = animationID;
|
33 |
mHP = hp;
|
34 |
}
|
35 |
|
36 |
};
|
37 |
|
38 |
} |
在脚本中执行发送数据包的动作,在Start方法中得到Socket对象。
1 |
public
JFSocket mJFsorket;
|
2 |
void
Start ()
|
3 |
{ |
4 |
mJFsorket = JFSocket.GetInstance();
|
5 |
} |
让角色发生移动的时候,调用该方法向服务端发送数据。
01 |
void
SendPlayerWorldMessage()
|
02 |
{ |
03 |
//组成新的结构体对象,包括主角坐标旋转等。
|
04 |
Vector3 PlayerTransform = transform.localPosition;
|
05 |
Vector3 PlayerRotation = transform.localRotation.eulerAngles;
|
06 |
//用short的话是2字节,为了节省包的长度。这里乘以100 避免使用float 4字节。当服务器接受到的时候小数点向前移动两位就是真实的float数据
|
07 |
short px = ( short )(PlayerTransform.x*100);
|
08 |
short py = ( short )(PlayerTransform.y*100);
|
09 |
short pz = ( short )(PlayerTransform.z*100);
|
10 |
short rx = ( short )(PlayerRotation.x*100);
|
11 |
short ry = ( short )(PlayerRotation.y*100);
|
12 |
short rz = ( short )(PlayerRotation.z*100);
|
13 |
byte equipID = 1;
|
14 |
byte animationID =9;
|
15 |
byte hp = 2;
|
16 |
JFPackage.WorldPackage wordPackage = new
JFPackage.WorldPackage(px,py,pz,rx,ry,rz,equipID,animationID,hp);
|
17 |
//通过Socket发送结构体对象
|
18 |
mJFsorket.SendMessage(wordPackage);
|
19 |
} |
接着就是客户端同步服务器的数据,目前是测试阶段所以写的比较简陋,不过原理都是一样的。哇咔咔!!
01 |
//上次同步时间 |
02 |
private float
mSynchronous;
|
03 |
void
Update ()
|
04 |
{ |
05 |
mSynchronous +=Time.deltaTime;
|
06 |
//在Update中每0.5s的时候同步一次
|
07 |
if (mSynchronous > 0.5f)
|
08 |
{
|
09 |
int count = mJFsorket.worldpackage.Count;
|
10 |
//当接受到的数据包长度大于0 开始同步
|
11 |
if (count > 0)
|
12 |
{
|
13 |
//遍历数据包中 每个点的坐标
|
14 |
foreach (JFPackage.WorldPackage wp in
mJFsorket.worldpackage)
|
15 |
{
|
16 |
float x = ( float )(wp.mPosx / 100.0f);
|
17 |
float y = ( float )(wp.mPosy /100.0f);
|
18 |
float z = ( float )(wp.mPosz /100.0f);
|
19 |
Debug.Log( "x = " + x +
" y = " + y+ " z = "
+ z);
|
20 |
//同步主角的新坐标
|
21 |
mPlayer.transform.position = new
Vector3 (x,y,z);
|
22 |
}
|
23 |
//清空数据包链表
|
24 |
mJFsorket.worldpackage.Clear();
|
25 |
}
|
26 |
mSynchronous = 0;
|
27 |
}
|
28 |
} |
主角移动的同时,通过Socket时时同步坐标喔。。有没有感觉这个牛头人非常帅气 哈哈哈。
对于Socket的使用,我相信没有比MSDN更加详细的了。 有关Socket 同步请求异步请求的地方可以参照MSDN 链接地址给出来了,好好学习吧,嘿嘿。http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.aspx
上述代码中我使用的是Thread() 没有使用协同任务StartCoroutine() ,原因是协同任务必需要继承MonoBehaviour,并且该脚本要绑定在游戏对象身上。问题绑定在游戏对象身上切换场景的时候这个脚本必然会释放,那么Socket肯定会断开连接,所以我需要用Thread,并且协同任务它并不是严格意义上的多线程。
2.HTTP
HTTP请求在Unity我相信用的会更少一些,因为HTTP会比SOCKET慢很多,因为它每次请求完都会断开。废话不说了, 我用HTTP请求制作用户的登录。用HTTP请求直接使用Unity自带的www类就可以,因为HTTP请求只有登录才会有, 所以我就在脚本中来完成, 使用 www 类 和 协同任务StartCoroutine()。
01 |
using
UnityEngine;
|
02 |
using
System.Collections;
|
03 |
using
System.Collections.Generic;
|
04 |
public
class LoginGlobe : MonoBehaviour {
|
05 |
|
06 |
void Start ()
|
07 |
{
|
08 |
//GET请求
|
09 |
StartCoroutine(GET( "http://xuanyusong.com/" ));
|
10 |
|
11 |
}
|
12 |
|
13 |
void Update ()
|
14 |
{
|
15 |
|
16 |
}
|
17 |
|
18 |
void OnGUI()
|
19 |
{
|
20 |
|
21 |
}
|
22 |
|
23 |
//登录
|
24 |
public void
LoginPressed()
|
25 |
{
|
26 |
//登录请求 POST 把参数写在字典用 通过www类来请求
|
27 |
Dictionary< string , string > dic = new
Dictionary< string , string > ();
|
28 |
//参数
|
29 |
dic.Add( "action" , "0" );
|
30 |
dic.Add( "usrname" , "xys" );
|
31 |
dic.Add( "psw" , "123456" );
|
32 |
|
33 |
StartCoroutine(POST( "http://192.168.1.12/login.php" ,dic));
|
34 |
|
35 |
}
|
36 |
//注册
|
37 |
public void
SingInPressed()
|
38 |
{
|
39 |
//注册请求 POST
|
40 |
Dictionary< string , string > dic = new
Dictionary< string , string > ();
|
41 |
dic.Add( "action" , "1" );
|
42 |
dic.Add( "usrname" , "xys" );
|
43 |
dic.Add( "psw" , "123456" );
|
44 |
|
45 |
StartCoroutine(POST( "http://192.168.1.12/login.php" ,dic));
|
46 |
}
|
47 |
|
48 |
//POST请求
|
49 |
IEnumerator POST( string url, Dictionary< string , string >
post)
|
50 |
{
|
51 |
WWWForm form = new
WWWForm();
|
52 |
foreach (KeyValuePair< string , string >
post_arg in
post)
|
53 |
{
|
54 |
form.AddField(post_arg.Key, post_arg.Value);
|
55 |
}
|
56 |
|
57 |
WWW www = new
WWW(url, form);
|
58 |
yield return
www;
|
59 |
|
60 |
if (www.error !=
null )
|
61 |
{
|
62 |
//POST请求失败
|
63 |
Debug.Log( "error is :" + www.error);
|
64 |
|
65 |
}
else
|
66 |
{
|
67 |
//POST请求成功
|
68 |
Debug.Log( "request ok : " + www.text);
|
69 |
}
|
70 |
}
|
71 |
|
72 |
//GET请求
|
73 |
IEnumerator GET( string url)
|
74 |
{
|
75 |
|
76 |
WWW www = new
WWW (url);
|
77 |
yield return
www;
|
78 |
|
79 |
if (www.error !=
null )
|
80 |
{
|
81 |
//GET请求失败
|
82 |
Debug.Log( "error is :" + www.error);
|
83 |
|
84 |
}
else
|
85 |
{
|
86 |
//GET请求成功
|
87 |
Debug.Log( "request ok : " + www.text);
|
88 |
}
|
89 |
}
|
90 |
|
91 |
} |
如果想通过HTTP传递二进制流的话 可以使用 下面的方法。
1 |
WWWForm wwwForm = new WWWForm();
|
2 |
byte [] byteStream = System.Text.Encoding.Default.GetBytes(stream);
|
3 |
wwwForm.AddBinaryData( "post" , byteStream);
|
4 |
www =
new WWW(Address, wwwForm);
|
目前Socket数据包还是没有进行加密算法,后期我会补上。欢迎讨论,互相学习互相进度 加油,蛤蛤。
转载http://www.xuanyusong.com/archives/1948
相关推荐
在实际开发中,Unity3D与Java间的Socket通信可能会遇到网络延迟、数据包丢失等问题,因此需要实现心跳机制以检测连接状态,以及错误处理机制来确保系统的稳定性和可靠性。此外,为了防止数据安全问题,可能还需要...
Unity中的Socket通信是游戏开发中实现网络交互的重要技术,它基于C#语言,允许服务器和客户端之间进行数据的高效传输。本教程将深入探讨如何在Unity中实现Socket通信,包括TCP连接、粘包/拆包问题的解决方案。 一、...
7. **Unity3D研究院之C#使用Socket与HTTP连接服务器传输数据包**: Unity支持使用C#的System.Net命名空间进行网络编程。Socket用于低级的TCP/IP通信,而HTTP则适用于与Web服务器交互。在游戏开发中,这可能涉及到...
Unity服务器Socket Demo是一个示例项目,它展示了如何在Unity引擎中构建一个简单的网络通信系统,主要涉及了Socket编程和Unity的C#脚本。Socket是网络编程中的基本组件,用于在不同设备之间建立连接并传输数据。在这...
在Unity游戏开发中,C# Socket网络模块是一个关键部分,用于实现游戏客户端和服务器之间的通信。Socket编程是一种基于TCP/IP协议的应用程序编程接口(API),它允许程序通过网络发送和接收数据。本教程将深入探讨...
在Unity中,通常使用C#语言实现Socket通信,通过System.Net命名空间中的Socket类来创建和管理Socket实例。Socket支持TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)两种传输协议,TCP保证...
Socket长连接是网络编程中的重要概念,主要用于保持客户端与服务器之间的持续通信状态,避免每次通信都需要重新建立连接的开销。在长连接中,一旦连接建立成功,就会保持该连接,直到某一方主动断开或者因为网络问题...
在C#中,可以使用`System.Net.Sockets.TcpClient`类创建客户端Socket连接到服务器,然后将登录信息封装成数据包并通过`NetworkStream`发送。服务器端接收到数据后解包验证,如果验证成功则返回确认信息。 5. **消息...
本篇文章将深入探讨如何使用C#实现WebSocket客户端,并进行性能测试。 首先,了解WebSocket的基本工作原理至关重要。WebSocket协议基于TCP连接,通过握手过程从HTTP/1.1协议升级而来。在握手过程中,客户端发送一个...
UnityTcp连接是一个与游戏开发相关的主题,主要涉及如何在Unity引擎中实现TCP网络通信。Unity是全球广泛应用的游戏开发平台,支持2D、3D、VR和AR等多种类型的项目。TCP(Transmission Control Protocol)是一种面向...
Socket通信允许Unity3D客户端与服务器之间建立连接,发送和接收数据。在本文中,我们将深入探讨Unity3D中的Socket通信,主要基于给出的代码示例进行解析。 首先,我们需要了解Socket的基本概念。Socket是网络编程中...
2. **数据传输**:PESocket支持同步和异步发送、接收数据,可以高效地处理大量并发连接,确保数据的可靠传输,同时避免了数据包丢失或乱序的问题。 3. **错误处理**:内建的错误检测和恢复机制,能够及时发现并处理...
标题 "supersocket 服务端+客户端...开发者可以深入研究代码,理解SuperSocket如何处理网络连接、数据传输以及错误处理,并根据需求对其进行扩展和定制,以适应各种实际应用场景,比如聊天室、文件传输、游戏服务器等。
首先,我们需要创建一个Socket实例,然后绑定到特定的IP地址和端口号,接着可以使用Connect方法连接到远程服务器,或者使用Listen方法开启监听等待客户端连接。 粘包问题及其处理: 在TCP协议中,由于其流式传输的...
2. **TCP/IP通信**:Unity中可以使用C#的System.Net命名空间来实现TCP/IP通信,创建Socket连接,发送和接收数据。这是对接网狐服务器的基础,因为服务器通常使用TCP协议来保证数据的可靠传输。 3. **JSON或protobuf...
在本项目中,我们探讨的是一个简单的聊天应用实现,它由Unity3D开发的客户端和C#编写的服务器端组成。这个系统的核心是通过网络通信技术实现用户之间的实时消息传递。接下来,我们将深入讨论其中涉及的关键知识点。 ...
标题中的"C#使用Protocol Buffer(ProtoBuf)进行Unity中的Socket通信"是指在Unity游戏引擎的C#编程环境中,利用Google的Protocol Buffer库进行Socket通信的一种技术。Protocol Buffer是一种高效的数据序列化协议,常...
Unity主要使用C#进行脚本编写,因此,连接服务端通常会通过C#的`System.Net`命名空间下的类,如`TcpClient`、`TcpListener`、`Socket`等。这些类用于建立TCP或UDP连接,发送和接收数据。 3. **ConnTester.cpp**: ...
本书将深入探讨如何使用Socket进行客户端-服务器通信,理解TCP/IP协议的工作原理,并实现在Unity中建立稳定的网络连接。读者将学习如何处理数据包的发送与接收,以及如何确保数据在网络中的可靠传输。 Unity引擎在...
2. **接受连接**:当有客户端请求连接时,服务器会调用Socket的Accept方法来接受连接,这将返回一个新的Socket对象,用于与该客户端进行数据交换。 3. **数据传输**:服务器通过Socket的Receive和Send方法接收并发送...