C#套接字只能发送一次

时间:2019-06-01 22:05:05

标签: c# sockets unity3d server client

我在Unity中创建服务器时遇到了问题。我的代码非常紧密地遵循了这些异步示例:

https://docs.microsoft.com/en-us/dotnet/framework/network-programming/asynchronous-server-socket-example

https://docs.microsoft.com/en-us/dotnet/framework/network-programming/asynchronous-client-socket-example

当前,服务器将正常启动,并且客户端可以连接。然后客户端可以发送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());
    }
}
}

2 个答案:

答案 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),而不是对自己的服务器进行编程。