如何在Socket编程中处理客户端断开连接?

时间:2013-01-12 08:19:21

标签: c# sockets network-programming

我已经使用套接字编写了服务器端代码,它工作正常但有一个问题我不知道如何处理这种情况:如果客户端只关闭应用程序而不发送断开请求,我的服务器端程序崩溃。我需要做些什么才能避免这种情况?请指导我,我是Socket编程的新手。

private void OnReceive(IAsyncResult result)
{
    try
    {
        Socket clientSocket = (Socket)result.AsyncState;
        clientSocket.EndReceive(result);

        command = responseMessage = string.Empty;
        command = ByteToString(receviedData);
        receviedData = new byte[30];

        if (command=="Connect")
        {
            ClientInfo clientInfo = new ClientInfo();
            clientInfo.socket = clientSocket;
            clientInfo.IP = clientSocket.RemoteEndPoint.ToString();
            connectedClients.Add(clientInfo);
            responseMessage = "Connection established...";
        }
        else if (command=="Disconnect")
        {
            for (int i = 0; i < connectedClients.Count; i++)
            {
                if (connectedClients[i].socket == clientSocket)
                {
                    connectedClients.RemoveAt(i);
                    break;
                }
            }
            clientSocket.Close();
        }
        else
        {
            responseMessage = "Error";
        }

        byte[] responseStatus = StringToByte(responseMessage);
        for (int i = 0; i < connectedClients.Count; i++)
        {
            if (connectedClients[i].socket==clientSocket)
            {
                connectedClients[i].socket.BeginSend(responseStatus, 0, responseStatus.Length,SocketFlags.None, new AsyncCallback(OnSend), connectedClients[i].socket);
                break;
            }
        }

    }
    catch(Exception ex)
    {
      throw new Exception(ex.Message);
    }
}

2 个答案:

答案 0 :(得分:2)

您的应用程序崩溃了,因为您在方法的catch块中抛出异常。

如果您不希望应用程序崩溃,则需要从throw new Exception(ex.Message);块中删除catch行。 将其替换为处理错误的代码,并将应用程序正常还原到安全状态。从阅读代码开始,应该从clientSocket

中删除connectedClients

其次,最好只使用throw;代替throw new Exception(ex.Message);throw;将重新抛出原始异常对象,从而保留堆栈跟踪和其他有助于调试软件的重要信息。 使用new Exception("Message")将使用当前堆栈跟踪创建一个全新的异常对象。

private void OnReceive(IAsyncResult result)
{
    try
    {
        Socket clientSocket = (Socket)result.AsyncState;
        clientSocket.EndReceive(result);

        command = responseMessage = string.Empty;
        command = ByteToString(receviedData);
        receviedData = new byte[30];

        if (command=="Connect")
        {
            ClientInfo clientInfo = new ClientInfo() {
               socket = clientSocket,
               IP = clientSocket.RemoteEndPoint.ToString(),
               }; 
            connectedClients.Add(clientInfo);
            responseMessage = "Connection established...";
        }
        else if (command=="Disconnect")
        {
            removeClientInfo(clientSocket);
            clientSocket.Close();
        }
        else
        {
            responseMessage = "Error";
        }

        byte[] responseStatus = StringToByte(responseMessage);
        for (int i = 0; i < connectedClients.Count; i++)
        {
            if (connectedClients[i].socket==clientSocket)
            {
                connectedClients[i].socket.BeginSend(responseStatus, 0, responseStatus.Length,SocketFlags.None, new AsyncCallback(OnSend), connectedClients[i].socket);
                break;
            }
        }

    }
    catch(Exception ex)
    {
      // add error handling and gracefully recover
      // caution: The way done here, might work, but it smells :-/
      removeClientInfo((Socket)result.AsyncState);
      ((Socket)result.AsyncState).Close();
    }
}

/// removes the client info from the connectedClients enumerable
private void removeClientInfo(Socket socket)
{
    for (int i = 0; i < connectedClients.Count; i++)
    {
        if (connectedClients[i].socket == socket)
        {
            connectedClients.RemoveAt(i);
            break;
        }
    }
}

答案 1 :(得分:1)

您在catch块中抛出了一个新的异常,除非您正在进行某些日志记录或类似操作,否则这没有多大意义。更改catch块,如:

catch(SocketException)
{ 
}

此外,您应该检查从EndReceive返回的读取字节数。如果您收到零字节,则表示客户端已关闭连接:

int numReceived = clientSocket.EndReceive(result);
if(numReceived == 0)
{
    //client has shutdown the connection
}