C#客户端 - 服务器套接字断开处理

时间:2016-01-15 21:09:49

标签: c# sockets client-server asyncsocket socketexception

我正在处理论文时,我现在有一个客户端 - 服务器代码。 我可以产生一个连接并发送数据,但是一旦客户端断开连接并尝试重新连接,一切都会横向移动,我似乎无法找出原因。抛出的异常太多了,我只是不知道从哪里开始捕捉它们。 做错了什么或者没有做到这一点是不允许nether客户端或服务器正确处理断开连接?!

这是我的ServerSide代码:

using System;
using System.Net;
using System.Net.Sockets;

namespace Server.Networking
{
public class ServerSocket
{
    private Socket _socket;
    Byte[] _buffer = new byte[61144];

    public ServerSocket()
    {
        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    }

    public void Bind(int port)
    {
        _socket.Bind(new IPEndPoint(IPAddress.Any, port));
    }

    public void Listener(int backlog)
    {
        _socket.Listen(backlog);
    }

    public void Accept()
    {
        _socket.BeginAccept(AcceptedCallback, null);
    }

    private void AcceptedCallback(IAsyncResult result)
    {
        try
        {
            Socket clientSocket = _socket.EndAccept(result);
            if (clientSocket.Connected)
            {
                Console.WriteLine("Client has connected!");
                _buffer = new byte[61144];
                clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
                Accept();
            }
            else
            {
                Console.WriteLine("Client hasn't connected!");
                return;
            }
        }catch(SocketException ex)
        {
            Console.WriteLine(ex.Message);
            close(clientSocket);
        }
    }

    private void ReceivedCallback(IAsyncResult result)
    {
        try
        {
            Socket clientSocket = result.AsyncState as Socket;
            SocketError SE;
            int bufferSize = clientSocket.EndReceive(result, out SE);
            if (bufferSize > 0)
            {
                if (SE == SocketError.Success)
                {
                    byte[] packet = new byte[bufferSize];
                    Array.Copy(_buffer, packet, packet.Length);
                    Console.WriteLine("Handling packet from IP:" + clientSocket.RemoteEndPoint.ToString());
                    //Handle packet stuff here.
                    PacketHandler.Handle(packet, clientSocket);
                    _buffer = new byte[61144];
                    clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
                }
                else
                {
                    close(clientSocket);
                }                    
            }
            else
            {
                Console.WriteLine("Probably received bad data.");
                close(clientSocket);
            }
        }
        catch (SocketException ex)
        {
            Console.WriteLine(ex.Message);
            close(clientSocket);
        }
    }

    public void close(Socket sock)
    {
        Console.WriteLine("Closing socket for IP:" + sock.RemoteEndPoint.ToString() + " and releasing resources.");
        sock.Dispose();
        sock.Close();
    }
}
}

这是我的客户端代码:

using System;
using System.Net;
using System.Linq;
using System.Net.Sockets;
using Client.Networking.Packets;
using System.Net.NetworkInformation;
using Client.Networking.Packets.Request;

namespace Client.Networking
{
public class ClientSocket
{
    private Socket _socket;
    private byte[] _buffer;

    public delegate void RaiseConnect(object source, TextArgs e);
    public static event EventHandler Disconnected;
    private static void RaiseDisconnect()
    {
        EventHandler handler = Disconnected;
        if(handler !=null)
        {
            handler(null, EventArgs.Empty);
        }
    }

    public ClientSocket()
    {
        udpbroadcast.Connect += new RaiseConnect(OnConnectRaise);
    }

    public string machineIP()
    {
        return Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork).ToString();
    }

    private void OnConnectRaise(object sender, TextArgs e)
    {
        CheckRegisteredRequest computer_name = new CheckRegisteredRequest(Environment.MachineName.ToString() + "," + machineIP());
        Connect(e.Message, 6556);
        Send(computer_name.Data);
    }

    public void Connect(string ipAddress, int port)
    {
        string ip = ipAddress;
        int porT = port;
        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IAsyncResult result =_socket.BeginConnect(new IPEndPoint(IPAddress.Parse(ip), port), ConnectCallback, null);
        bool success = result.AsyncWaitHandle.WaitOne(5000, true);
        if(!success)
        {
            _socket.Close();
            Console.WriteLine("Failed to connect to server. Trying again.");
            Connect(ip, port);
        }
    }

    private void ConnectCallback(IAsyncResult result)
    {
        try {
            if (_socket.Connected)
            {
                Console.WriteLine("Connected to the server!");
                _buffer = new byte[61144];
                _socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, null);
            }
            else
            {
                Console.WriteLine("Could not connect.");
                Close(_socket);
            }
        }
        catch(SocketException ex)
        {
            Console.WriteLine("ClientSocket ConnectCallback - "+ex.Message);
            Close(_socket);
        }
    }

    private void ReceivedCallback(IAsyncResult result)
    {
        try
        {
            SocketError SE;
            int buflength = _socket.EndReceive(result, out SE);
            if (buflength > 0)
            {
                if(SE == SocketError.Success)
                {
                    byte[] packet = new byte[buflength];
                    Array.Copy(_buffer, packet, packet.Length);

                    //Handle the Package
                    PacketHandler.Handle(packet, _socket);

                    _buffer = new byte[61144];
                    _socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, null);
                }
                else
                {
                    Close(_socket);
                }
            }
            else
            {
                Close(_socket);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("ClientSocket ReceivedCallback - " + ex.Message);
            Close(_socket);
        }
    }

    public void Send(byte[] data)
    {
        byte[] send = new byte[data.Length];
        send = data;
        if( _socket.Connected)
        {
            _socket.Send(data);
        }
        else
        {
            Console.WriteLine("Not connected yet!");
            Close(_socket);
        }
    }

    public bool connectionStatus()
    {
        return _socket.Connected;
    }

    public static void Close(Socket sock)
    {
        Console.WriteLine("Closing the socket and releasing resources.");
        sock.Dispose();
        sock.Close();
        RaiseDisconnect();
    }
}
}

2 个答案:

答案 0 :(得分:1)

我能想到的两件事。 Socket上的文档建议在Close()之前先调用Shutdown()

此外,您无法重用套接字对象。因此,在尝试新连接之前,请确保使用新的Socket对象,可以通过_socket = new Socket(),也可以使用全新的ServerSocket / ClientSocket。

答案 1 :(得分:0)

我设法让它使用以下代码。在服务器代码中,我通过以下方式启动BeginReceive witihn AcceptedCallback

clientSocket.BeginReceive(new byte[] {0}, 0, 0, 0, ReceivedCallback, clientSocket);

然后在 ReceivedCallback 中,我会以不同的方式执行BeginReceive:

clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);

虽然受到例外的困扰,但似乎我已经跳过检查我在初始连接中收到的内容。

在客户端代码中,在 ConnectCallback 方法中,我确实开始接收:

_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, null);

ReceivedCallback 方法中,我反向执行了BeginReceive:

_socket.BeginReceive(new byte[] { 0 }, 0, 0, 0, ReceivedCallback, null);

经过三个小时的调试,这对我来说很有意义。 每次接受连接时,服务器都会生成一个新的套接字对象,以避免线程化。因此,在服务器端的AcceptedCallback方法中,初始的_socket.BeginReceive应该通过空字节数组调用ReceivedCallback方法来仅触发它。然后在ReceivedCallback中使用自定义为套接字接收长度的数组执行BeginReceive。在客户方面,它是相反的。

这是我的服务器端代码:

    private Socket _socket;
    Byte[] _buffer = new byte[61144];

    public ServerSocket()
    {
        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    }

    public void Bind(int port)
    {
        _socket.Bind(new IPEndPoint(IPAddress.Any, port));
    }

    public void Listener(int backlog)
    {
        _socket.Listen(backlog);
    }

    public void Accept()
    {
        _socket.BeginAccept(AcceptedCallback, null);
    }

    private void AcceptedCallback(IAsyncResult result)
    {
        Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        try
        {
            Console.WriteLine("We accepted a connection.");
            clientSocket = _socket.EndAccept(result);
            if (clientSocket.Connected)
            {
                Console.WriteLine("Client has connected!");
                _buffer = new byte[61144];
                //clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
                clientSocket.BeginReceive(new byte[] {0}, 0, 0, 0, ReceivedCallback, clientSocket);
                Accept();
            }
            else
            {
                Console.WriteLine("Client hasn't connected!");
                Accept();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Socket was probably forcefully closed." + ex.Message);
            Console.WriteLine("Continue accepting other connections.");
            clientSocket.Close();
            Accept();
        }
    }

    private void ReceivedCallback(IAsyncResult result)
    {
        Socket clientSocket = result.AsyncState as Socket;
        SocketError ER;
        try
        {
            int bufferSize = clientSocket.EndReceive(result, out ER);
            if (ER == SocketError.Success)
            {
                byte[] packet = new byte[bufferSize];
                Array.Copy(_buffer, packet, packet.Length);
                Console.WriteLine("Handling packet from IP:" + clientSocket.RemoteEndPoint.ToString());
                //Handle packet stuff here.
                PacketHandler.Handle(packet, clientSocket);
                _buffer = new byte[61144];
                clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
                //clientSocket.BeginReceive(new byte[] { 0 }, 0, 0, 0, ReceivedCallback, clientSocket);
            }
            else
            {
                Console.WriteLine("No bytes received, we're closing the connection.");
                clientSocket.Close();
            }
        }catch(SocketException ex)
        {
            Console.WriteLine("We caught a socket exception:" + ex.Message);
            clientSocket.Close();
        }
    }

这是我的客户端代码:

private Socket _socket;
    private CheckRegisteredRequest computer_name;
    private bool isClosed;
    private byte[] _buffer;
    public delegate void RaiseConnect(object source, TextArgs e);

    public static event EventHandler Disconnected;
    private static void RaiseDisconnect()
    {
        EventHandler handler = Disconnected;
        if (handler != null)
        {
            handler(null, EventArgs.Empty);
        }
    }

    public ClientSocket()
    {
        isClosed = true;
        udpbroadcast.Connect += new RaiseConnect(OnConnectRaise);
        computer_name = new CheckRegisteredRequest(Environment.MachineName.ToString() + "," + machineIP());
    }

    private void OnConnectRaise(object sender, TextArgs e)
    {
        if(!isClosed)
        {
            _socket.Close();
            Connect(e.Message, 6556);
        }
        else
        {
            Connect(e.Message, 6556);
        }
    }

    public void Connect(string ipAddress, int port)
    {
        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _socket.BeginConnect(new IPEndPoint(IPAddress.Parse(ipAddress), port), ConnectCallback, null);
        isClosed = false;
        /*IAsyncResult result = 
        bool success = result.AsyncWaitHandle.WaitOne(5000, true);
        if (!success)
        {
            _socket.Shutdown(SocketShutdown.Both);
            _socket.Close();
            Console.WriteLine("Failed to connect to server. Trying again.");
            RaiseDisconnect();
        }*/
    }

    private void ConnectCallback(IAsyncResult result)
    {
        try
        {
            if(_socket.Connected)
            {
                _socket.EndConnect(result);
                Console.WriteLine("We initiated a connection to the server.");
                Console.WriteLine("Connected to the server!");
                Send(computer_name.Data);
                _buffer = new byte[61144];
                _socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, null);
            }
            else
            {
                Console.WriteLine("Could not connect.");
                if(!isClosed)
                {
                    _socket.Close();
                    isClosed = true;
                    RaiseDisconnect();
                }
                else
                {
                    isClosed = true;
                    RaiseDisconnect();
                }
            }
        }
        catch (SocketException ex)
        {
            Console.WriteLine("ConnectCallback Exception Caught.");
            Console.WriteLine("Shutting down and closing socket for reusal.");
            if (!isClosed)
            {
                _socket.Close();
                isClosed = true;
                RaiseDisconnect();
            }
            else
            {
                isClosed = true;
                RaiseDisconnect();
            }
        }
    }

    private void ReceivedCallback(IAsyncResult result)
    {
        try
        {
            SocketError SE;
            int buflength = _socket.EndReceive(result, out SE);
            if (SE == SocketError.Success)
            {
                byte[] packet = new byte[buflength];
                Array.Copy(_buffer, packet, packet.Length);

                //Handle the Package
                PacketHandler.Handle(packet, _socket);

                _buffer = new byte[61144];
                //_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, null);
                _socket.BeginReceive(new byte[] { 0 }, 0, 0, 0, ReceivedCallback, null);
            }
            else
            {
                Console.WriteLine("No bytes received, we're closing the connection.");
                if (!isClosed)
                {
                    _socket.Close();
                    isClosed = true;
                    RaiseDisconnect();
                }
                else
                {
                    isClosed = true;
                    RaiseDisconnect();
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("ReceivedCallback Exception Caught.");
            Console.WriteLine("Shutting down and closing socket for reusal.");
            if (!isClosed)
            {
                _socket.Close();
                isClosed = true;
                RaiseDisconnect();
            }
            else
            {
                isClosed = true;
                RaiseDisconnect();
            }
        }
    }

    public void Send(byte[] data)
    {
        byte[] send = new byte[data.Length];
        send = data;
        if (_socket.Connected)
        {
            _socket.Send(data);
        }
        else
        {
            Console.WriteLine("We're not connected yet!");
            if (!isClosed)
            {
                _socket.Close();
                isClosed = true;
                RaiseDisconnect();
            }
            else
            {
                isClosed = true;
                RaiseDisconnect();
            }
        }
    }

    public bool connectionStatus()
    {
        return _socket.Connected;
    }

    public string machineIP()
    {
        return Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork).ToString();
    }