receiving TCP connection issues

2019-07-17 04:39发布

问题:

I've managed to set it up so my unity app can take in tcp data. However when I run the project the entire application freezes and won't do anything until it has received a message. Then, once a message has been received, it prints that message out and won't allow my client to connect to it again.

This code is the entirety of my TCP reading class, is there something silly I'm doing here that is causing this?

Is there a better way to read in TCP data?

using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System;
using System.IO;

public class TCPConnection: MonoBehaviour 
{
    public string ip_address = "";
    public int port_number = 0;

     void Start()
    {

        try
        {
            IPAddress ipAddress = IPAddress.Parse(ip_address);
            TcpListener listener = new TcpListener(ipAddress, port_number);
            listener.Start();
            print("The server is running at port " + port_number);
            print("The local end point is :" + listener.LocalEndpoint);
            print("Waiting for connection.....");

            Socket socket = listener.AcceptSocket();
            print("Connection accepted from " + socket.RemoteEndPoint);

            byte[] b = new byte[100];
            int k = socket.Receive(b);
            print("recieved...");
            for (int i = 0; i < k; i++)
                print (Convert.ToChar(b[i]));

            ASCIIEncoding ascii = new ASCIIEncoding();
            socket.Send(ascii.GetBytes("The string was recieved by the server"));
            print("\nSent ack");

        }

        catch (Exception e)
        {
            print("error...." + e.Message);
        }

    }
}

回答1:

listener.AcceptSocket and socket.Receive are a blocking calls. So it is normal that your UI freezes. And after you have accepted the first connection, you never call listener.AcceptSocke again to get a new collection.

The common way to use these methods are using async calls, threads or Tasks.

EDIT

An example:

void Start()
{
    Task.Factory.StartNew(() =>
        {
            TcpListener listener = new TcpListener(IPAddress.Any, 12345);
            listener.Start();

            while (true)
            {
                Socket socket = listener.AcceptSocket();
                Task.Factory.StartNew(() =>
                {
                    byte[] b = new byte[100];
                    int k = socket.Receive(b);
                });
            }
        });
}


回答2:

The socket.Receive(b); and Accept() will block the current thread until you receive data, you can do several things here:

1) Create a separated thread that received data, and put it into a queue that is checked by a main thread. But this isn't recommented with many client connecting.

2) You can use the asynchronous method of sockets: an example is shown here: http://csharp.vanlangen.biz/network-programming/async-sockets/asyncsocketreader/ There is also an example of a non-blocking listener.

an async listener look something like this:

public class SocketEventArgs : EventArgs
{
    public Socket Socket { get; private set; }

    public SocketEventArgs(Socket socket)
    {
        Socket = socket;
    }
}

/// <author>Jeroen van Langen</author>
/// <source>http://http://csharp.vanlangen.biz/network-programming/async-sockets/easysocketlistener/</source>
public class EasySocketListener : IDisposable
{
    private Socket _socket;

    public void Start(int port)
    {
        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _socket.Bind(new IPEndPoint(IPAddress.Any, port));
        _socket.Listen(8);

        StartAccepting();
    }

    private void StartAccepting()
    {
        try
        {
            _socket.BeginAccept((asyncResult) =>
            {
                try
                {
                    Socket clientSocket = _socket.EndAccept(asyncResult);
                    if (OnSocketAccept != null)
                        OnSocketAccept(this, new SocketEventArgs(clientSocket));

                    StartAccepting();
                }
                catch { }
            }, null);
        }
        catch { }
    }

    public void Dispose()
    {
        if (_socket != null)
        {
            _socket.Dispose();
            _socket = null;
        }
    }

    public event EventHandler<SocketEventArgs> OnSocketAccept;
}

The OnSocketAccept will be called when there is a new client connected.