我在Unity中创建服务器时遇到了问题。我的代码非常紧密地遵循了这些异步示例:
当前,服务器将正常启动,并且客户端可以连接。然后客户端可以发送1条消息并收到1条响应。此后,发送将不再起作用。
我的控制台输出如下所示: https://imgur.com/a/THJyWLI
如果有人知道这有什么问题,我将非常感谢。
代码(对于代码质量,我深表歉意,这是一团糟,因为我一直试图使其正常工作)
服务器:
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System;
using UnityEngine;
public class TCP_Server : ServerType {
#region Threads
private Thread receiveThread;
private List<ThreadTime> sendThreads;
private void FlushThreads() {
if (sendThreads == null) {
return;
}
for (int i = 0; i < sendThreads.Count; i++) {
if (sendThreads[i].Done()) {
sendThreads.RemoveAt(i);
i--;
}
}
}
#endregion
public ManualResetEvent allDone = new ManualResetEvent(false);
private Packet testPacket = new Packet(0, 0, 0, "Server response template");
private byte[] TestData() {
List<Packet> p = new List<Packet>();
p.Add(testPacket);
return Packet.ToByteData(p);
}
private Socket listener;
static int Main(string[] args) {
TCP_Server s = new TCP_Server();
s.StartServer();
return 0;
}
public override void StartServer() {
base.StartServer();
sendThreads = new List<ThreadTime>();
receiveThread = new Thread(new ThreadStart(StartServerThread));
receiveThread.IsBackground = true;
receiveThread.Start();
}
public override void StopServer() {
base.StopServer();
}
public void StartServerThread() {
MonoBehaviour.print("Creating server");
//IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPHostEntry ipHostInfo = Dns.GetHostEntry("127.0.0.1");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, Server.PORT);
listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try {
listener.Bind(localEndPoint);
listener.Listen(100);
while (true) {
allDone.Reset();
MonoBehaviour.print("Starting to listen");
listener.BeginAccept(new AsyncCallback(ReceiveData), listener);
allDone.WaitOne();
}
} catch (System.Exception e) {
MonoBehaviour.print(e);
}
}
private void ReceiveData(IAsyncResult ar) {
allDone.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
TcpStateObject state = new TcpStateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, TcpStateObject.bufferSize, 0, new AsyncCallback(ReadCallback), state);
}
private void ReadCallback(IAsyncResult ar) {
TcpStateObject state = (TcpStateObject)ar.AsyncState;
Socket handler = state.workSocket;
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0) {
state.SaveBuffer(bytesRead);
if (state.EndOfData()) {
MonoBehaviour.print("Server received data: " + state.data.Count);
List<Packet> reqs = Packet.ToPacketData(state.ToByteArray());
foreach (Packet p in reqs) {
requests.Add(p);
}
Send(handler, TestData());
} else {
handler.BeginReceive(state.buffer, 0, TcpStateObject.bufferSize, 0, new AsyncCallback(ReadCallback), state);
}
} else {
}
}
private void Send(Socket handler, byte[] data) {
FlushThreads();
ThreadTime t = ThreadTime.New(delegate () { SendThread(handler, data); });
sendThreads.Add(t);
t.thread.Start();
}
private void SendThread(Socket handler, byte[] data) {
handler.BeginSend(data, 0, data.Length, 0, new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar) {
try {
Socket handler = (Socket)ar.AsyncState;
int bytesSent = handler.EndSend(ar);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
} catch (Exception e) {
MonoBehaviour.print(e.ToString());
}
}
}
客户:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
public class TCP_Client : ClientType {
private Thread responseThread;
private List<ThreadTime> sendThreads;
private void FlushThreads() {
if (sendThreads == null) {
return;
}
for (int i = 0; i < sendThreads.Count; i++) {
if (sendThreads[i].Done()) {
sendThreads.RemoveAt(i);
i--;
}
}
}
private ManualResetEvent connectDone = new ManualResetEvent(false);
private ManualResetEvent sendDone = new ManualResetEvent(false);
private ManualResetEvent receiveDone = new ManualResetEvent(false);
private Socket client;
public override void SendRequests() {
FlushThreads();
ThreadTime t = ThreadTime.New(new ThreadStart(SendRequestsThread));
sendThreads.Add(t);
t.thread.Start();
}
public override void Connect() {
base.Connect();
sendThreads = new List<ThreadTime>();
responseThread = new Thread(new ThreadStart(ConnectThread));
responseThread.IsBackground = true;
responseThread.Start();
}
public void ConnectThread() {
MonoBehaviour.print("Connecting to server...");
try {
//IPHostEntry ipHostInfo = Dns.GetHostEntry("");
IPHostEntry ipHostInfo = Dns.GetHostEntry("127.0.0.1");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, Server.PORT);
client = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
MonoBehaviour.print("Client connect status: " + client.Connected);
client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
MonoBehaviour.print("Client connect status: " + client.Connected);
} catch (Exception e) {
MonoBehaviour.print(e);
}
}
public override void Disconnect() {
base.Disconnect();
Socket client = null;
if (client == null) {
return;
}
client.Shutdown(SocketShutdown.Both);
client.Close();
client = null;
}
private void SendRequestsThread() {
MonoBehaviour.print("Sending " + requests.Count + " requests");
byte[] data = Packet.ToByteData(requests);
requests.Clear();
Send(client, data);
sendDone.WaitOne();
Receive(client);
receiveDone.WaitOne();
}
private void ConnectCallback(IAsyncResult ar) {
try {
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
MonoBehaviour.print($"Socket connected to {client.RemoteEndPoint.ToString()}");
// Signal that the connection has been made.
connectDone.Set();
} catch (Exception e) {
MonoBehaviour.print(e.ToString());
}
}
private void Receive(Socket client) {
try {
// Create the state object.
TcpStateObject state = new TcpStateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, TcpStateObject.bufferSize, 0, new AsyncCallback(ReceiveCallback), state);
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
private void ReceiveCallback(IAsyncResult ar) {
try {
// Retrieve the state object and the client socket
// from the asynchronous state object.
TcpStateObject state = (TcpStateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0) {
// There might be more data, so store the data received so far.
state.SaveBuffer(bytesRead);
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, TcpStateObject.bufferSize, 0, new AsyncCallback(ReceiveCallback), state);
} else {
state.EndOfData();
MonoBehaviour.print("Client received data: " + state.data.Count);
List<Packet> ress = Packet.ToPacketData(state.ToByteArray());
foreach (Packet p in ress) {
responses.Add(p);
}
receiveDone.Set();
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
private void Send(Socket client, byte[] data) {
MonoBehaviour.print("Client sends data: " + data.Length);
client.BeginSend(data, 0, data.Length, 0, new AsyncCallback(SendCallback), client);
}
private void SendCallback(IAsyncResult ar) {
try {
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
MonoBehaviour.print("Send start: " + client.Connected);
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
// Signal that all bytes have been sent.
sendDone.Set();
MonoBehaviour.print("Send done: " + bytesSent);
} catch (Exception e) {
MonoBehaviour.print(e.ToString());
}
}
}
答案 0 :(得分:0)
private static void SendCallback(IAsyncResult ar) {
try {
Socket handler = (Socket)ar.AsyncState;
int bytesSent = handler.EndSend(ar);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
} catch (Exception e) {
MonoBehaviour.print(e.ToString());
}
}
handler.ShutDown(); 你为什么要关机?服务器发送后并关闭两个套接字。如果使用回显服务器示例,请尝试实现您的逻辑并且不要关闭套接字
答案 1 :(得分:0)
我决定使用现有的网络库(NetworkComms.net),而不是对自己的服务器进行编程。