如何处理客户端断开在套接字编程

本文关键字:断开 套接字 编程 客户端 何处理 处理 | 更新日期: 2023-09-27 17:51:22

我使用套接字写了一个服务器端代码,它工作得很好,但有一个问题我不知道如何处理这种情况:如果客户端只是关闭应用程序而不发送断开请求,我的服务器端程序崩溃。我需要做些什么来避免这种情况?请指导我,我是新的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);
    }
}

如何处理客户端断开在套接字编程

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

如果你不想让你的应用程序崩溃,你需要从catch块中删除throw new Exception(ex.Message);行。将其替换为处理错误并将应用程序优雅地恢复到安全状态的代码。从您的代码来看,这应该通过从connectedClients

中删除clientSocket来完成。

其次,最好只使用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;
        }
    }
}

您在catch块内抛出了一个新的异常,除非您正在做一些日志记录或类似的事情,否则这没有多大意义。将catch块更改为:

catch(SocketException)
{ 
}

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

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