【问题标题】:TCP Socket client Async - connection handlingTCP Socket 客户端异步 - 连接处理
【发布时间】:2016-05-24 02:16:21
【问题描述】:

我在 TCP 客户端套接字中的连接处理有问题。

此代码应连接到 localhost 的 4444 端口并侦听来自此 TCP 服务器的所有传入数据。

我需要为此编写连接处理。例如,如果在尝试连接时服务器没有响应,它应该重新尝试连接,或者如果连接已准备好并且在接收到一些数据后 TCP 服务器将关闭连接 TCP 客户端应该重新尝试重新连接。

谁能帮我解决这个问题

这是我此刻所拥有的

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

public class TCPClientNew : MonoBehaviour {

    private Socket _clientSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
    private byte[] _recieveBuffer = new byte[8142];

    private void StartClient()
    {
        try
        {
            _clientSocket.Connect(new IPEndPoint(IPAddress.Loopback,4444));
        }
        catch(SocketException ex)
        {
            Debug.Log(ex.Message);

            // Try to reconnect ??  TODO
        }
        Debug.Log ("connected");

        _clientSocket.BeginReceive(_recieveBuffer,0,_recieveBuffer.Length,SocketFlags.None,new AsyncCallback(ReceiveCallback),null);

    }

    private void ReceiveCallback(IAsyncResult AR)
    {
        //Check how much bytes are recieved and call EndRecieve to finalize handshake
        int recieved = _clientSocket.EndReceive(AR);

        if(recieved <= 0)
            return;

        //Copy the recieved data into new buffer , to avoid null bytes
        byte[] recData = new byte[recieved];
        Buffer.BlockCopy(_recieveBuffer,0,recData,0,recieved);


        //Processing received data
        Debug.Log (System.Text.Encoding.ASCII.GetString(recData));



        //Start receiving again
        _clientSocket.BeginReceive(_recieveBuffer,0,_recieveBuffer.Length,SocketFlags.None,new AsyncCallback(ReceiveCallback),null);
    }

    private void SendData(byte[] data)
    {
        SocketAsyncEventArgs socketAsyncData = new SocketAsyncEventArgs();
        socketAsyncData.SetBuffer(data,0,data.Length);
        _clientSocket.SendAsync(socketAsyncData);
    }

    void Start()
    {
        StartClient ();
    }
}

【问题讨论】:

    标签: c# sockets unity3d tcp asyncsocket


    【解决方案1】:

    您想要的是一种在连接失败时继续重试连接的方法。如果在读取过程中出现异常,您想查看我们是否仍然连接,如果没有则重新连接。我在 Connect() 方法中添加了一个循环,等待 1 秒后重试连接。

    在接收回调中,我放了一个try/catch,如果有异常我会回到Connect()方法重试连接。

    public class TCPClientNew
    {
    
        private Socket _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        private byte[] _recieveBuffer = new byte[8142];
    
        private void Connect()
        {
            bool isConnected = false;
    
            // Keep trying to connect
            while (!isConnected)
            {
                try
                {
                    _clientSocket.Connect(new IPEndPoint(IPAddress.Loopback, 4444));
                    // If we got here without an exception we should be connected to the server
                    isConnected = true;
                }
                catch (SocketException ex)
                {
                    Debug.Log(ex.Message);
    
                    // Wait 1 second before trying to connect again
                    Thread.Sleep(1000);
                }
            }
    
            // We are now connected, start to receive
            _clientSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
        }
    
        private void ReceiveCallback(IAsyncResult AR)
        {
            //Check how much bytes are recieved and call EndRecieve to finalize handshake
            try
            {
                int recieved = _clientSocket.EndReceive(AR);
    
                if (recieved <= 0)
                    return;
    
                //Copy the recieved data into new buffer , to avoid null bytes
                byte[] recData = new byte[recieved];
                Buffer.BlockCopy(_recieveBuffer, 0, recData, 0, recieved);
    
                //Start receiving again
                _clientSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
            }
            catch (SocketException ex)
            {
                Debug.Log(ex.Message);
    
                // If the socket connection was lost, we need to reconnect
                if (!_clientSocket.Connected)
                {
                    Connect();
                }
                else
                {
                    //Just a read error, we are still connected
                    _clientSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
                }
            }
        }
    
        private void SendData(byte[] data)
        {
            SocketAsyncEventArgs socketAsyncData = new SocketAsyncEventArgs();
            socketAsyncData.SetBuffer(data, 0, data.Length);
            _clientSocket.SendAsync(socketAsyncData);
        }
    }
    

    【讨论】:

    • 嗯...仅代码的答案,尤其是这种长度的答案,对于未来的用户(可能还有提问者)来说可能很难遵循。您能否对您所做的更改添加一些解释,最好指出 OP 出了什么问题,以及您修复了什么?
    • @Serlite 当然,问题。我只是通过更改几行来修改 OPs 类。我来评论
    • @Mangist 如果 TCP 服务器没有响应,我尝试了通过此解决方案冻结 Unity 的方法。可能吗?还是我以错误的方式执行它?
    • 在另一个线程中运行 TcpClient。不要在你的 UI 线程中运行它。使用 Thread.Start() 或 TaskFactory。
    • @Mangist 这解决了我的冻结问题,但是在一个连接被拒绝后,它在日志中显示“无效参数”并且不再连接。
    猜你喜欢
    • 1970-01-01
    • 2016-03-31
    • 2016-09-15
    • 1970-01-01
    • 2014-04-07
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 2013-05-22
    相关资源
    最近更新 更多