我想用Unity制作套接字网络程序,所以我制作了测试项目并在该项目中添加了NetworkManager
类和PacketManager
类进行测试。
程序启动时,我在connect()
中调用NetworkManager
方法,然后网络连接成功。我必须将数据包发送到字节流以便发送到服务器。所以我使用编组和调用PacketManager
方法使getBytes()
类(静态)。但它不起作用(统一程序终止)。
这是我的脚本
Move.cs
using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System.Net;
using System;
using System.Runtime.InteropServices;
public class move : MonoBehaviour {
private NetworkManager nManager;
// Use this for initialization
void Start () {
Debug.Log ("start");
nManager = new NetworkManager ();
nManager.connect ();
packet p = new packet();
p.type = 100;
p.msg = "abcdabcd";
byte[] array = PacketManager.getBytes (p);
}
// Update is called once per frame
void Update () {
}
}
NetworkManager.cs
using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System.Net;
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct packet
{
public int type;
public int number;
public int room;
public float x, y, z;
public float rotate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
public string msg;
}
public class NetworkManager : MonoBehaviour
{
private const string serverIP = "127.0.0.1";
private const int portNum = 9090;
private const int buffersize = 128;
private static TcpClient client = null;
private static NetworkStream netStream = null;
public NetworkManager() {}
public Boolean connect()
{
Boolean success = false;
try
{
Debug.Log("try to connenct..");
client = new TcpClient(serverIP, portNum);
netStream = client.GetStream();
Debug.Log("connected success!");
}
catch (Exception e)
{
success = false;
Debug.Log(e.Message);
}
return success;
}
public void sendPacket(packet p)
{
byte[] array = PacketManager.getBytes(p);
netStream.Write(array, 0, buffersize);
}
public packet recvPacket()
{
packet p = new packet();
byte[] bytebuffer = new Byte[buffersize];
int totalByteRcvd = 0;
int bytesRcvd = 0;
while (totalByteRcvd < buffersize)
{
if ((bytesRcvd = netStream.Read(bytebuffer, totalByteRcvd, buffersize - totalByteRcvd)) == 0)
{
p = PacketManager.BytesToSturct<packet>(bytebuffer);
break;
}
totalByteRcvd += bytesRcvd;
Debug.Log("byte : " + totalByteRcvd);
}
return p;
}
}
PacketManager.cs
using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System.Net;
using System;
using System.Runtime.InteropServices;
public class PacketManager : MonoBehaviour
{
public static byte[] getBytes(object str)
{
int size = Marshal.SizeOf(str);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(str, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr;
}
public static T BytesToSturct<T>(byte[] buffer) where T : struct
{
int size = Marshal.SizeOf(typeof(T));
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(buffer, 0, ptr, size);
T obj = (T)Marshal.PtrToStructure(ptr, typeof(T));
Marshal.FreeHGlobal(ptr);
return obj;
}
}
如果我删除:
byte[] array = PacketManager.getBytes (p);
在move.cs
中,日志打印得很好,但如果我调用任何方法(不仅仅是该方法),程序也会终止。
有什么问题?
答案 0 :(得分:1)
“Unity编辑已经停止工作”消息是流行和统一程序 突然退出并转到桌面(我必须重新打开统一程序)所以我 无法检查log msg
我可以在您的代码中发现一些问题。
1 。您使用的synchronous socket
没有Thread
。使用synchronous socket
时,您必须使用Thread
,否则它会在等待客户端连接,连接到服务器或等待从客户端接收时冻结Unity。
另一种解决方案是使用asynchronous socket
。您不需要Thread
来使用它。
<强> 2 即可。while (totalByteRcvd < buffersize)
。这将立即冻结Unity直到totalByteRcvd >= buffersize
,在此之前,netStream.Read
必须返回,但由于#1 中的问题,这不会很快发生。
所以让你的recvPacket()
函数成为一个void函数,就像这样调用它:
receive();
void receive()
{
System.Threading.Thread socketThread = new System.Threading.Thread(recvPacket);
socketThread.Start();
}
这可以解决你的冰冻问题。如果这不起作用,那么代码中还存在其他问题。使用here中的工作服务器套接字代码。您只需将其转换为客户端代码即可。