0

我有一个使用 WCF 服务的小型文件传输应用程序,它通过 tcp 套接字发送文件和文件夹。
我的问题是,当我从客户端取消传输操作(后台工作人员)时,服务器仍然冻结client.Receive,它应该给我这个异常:An existing connection was forcibly closed by the remote host,但它没有,尽管在客户端,listener.Connected变成false套接字。已连接成为false
我需要获取此异常并处理它,以便我可以关闭流和套接字并准备好接收另一个任务!

客户端:

private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        List<Job> Jobs = (List<Job>)e.Argument;
        using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
        {
            IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 0);
            listener.Bind(endpoint);
            listener.Listen(1);
            client.ConnectToClient((IPEndPoint)listener.LocalEndPoint);
            Socket socket = listener.Accept();
            foreach (Job job in Jobs)
            {
                if (job.IsFile)
                   {
                      if (job.IsSend)
                      { SendFile(socket, job, e); }  //here i send a single file.
         //           else
         //           { ReceiveFile(socket, job, e); }
                   }
         //        else
         //        {
         //           if (job.IsSend)
         //           { SendDir(socket, job, e); }
         //           else
         //           { ReceiveDir(socket, job, e); }
         //        }
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    socket.Dispose();
                    listener.Dispose();
                    Console.WriteLine(socket.Connected + "  " + listener.Connected);  
                    //it prints "FALSE FALSE"
                    return;
                }
            }
        }
    }

private void SendFile(Socket socket, Job job, DoWorkEventArgs e)
    {
        UpdateInfo(job.Name, job.Icon);              //update GUI with file icon and name.
        client.ReceiveFile((_File)job.Argument, bufferSize); //tell the client to start receiving
        SendX(socket, ((_File)job.Argument).Path, e);    //start sending..
    }

private void SendX(Socket socket, string filePath, DoWorkEventArgs e)
    {
        using (Stream stream = File.OpenRead(filePath))
        {
            byte[] buffer = new byte[bufferSize];
            long sum = 0;
            int count = 0;
            while (sum < stream.Length)
            {
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }
                count = stream.Read(buffer, 0, buffer.Length);
                socket.Send(buffer, 0, count, SocketFlags.None);
                sum += count;
                SumAll += count;
                worker.ReportProgress((int)((sum * 100) / stream.Length));
            } 
        }
    }

服务器端:

public void ConnectToClient(IPEndPoint endpoint)
    {
        if (client == null)
        {
            Thread th = new Thread(unused => ConnectTh(endpoint));
            th.Start();
        }
    }
    private void ConnectTh(IPEndPoint endpoint)
    {
        client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        client.Connect(IPAddress.Parse("127.0.0.1"), endpoint.Port);
    }


public void ReceiveFile(_File file, int bufferSize)
    {
        System.Threading.Thread th = new System.Threading.Thread(unused => ReceiveX(client, file.Name, file.Size, bufferSize));
        th.Start();
    }

private void ReceiveX(Socket client, string destPath, long size, int bufferSize)
    {
        try
        {
            using (Stream stream = File.Create(destPath))
            {
                byte[] buffer = new byte[bufferSize];
                long sum = 0;
                int count = 0;
                while (sum < size)
                {
                    int bytesToReceive = (int)Math.Min(buffer.Length, size - sum);
                    count = client.Receive(buffer, 0, bytesToReceive, SocketFlags.None);
                    stream.Write(buffer, 0, count);
                    sum += count;
                }
            }
        }
        catch
        {
            if (File.Exists(destPath))
                File.Delete(destPath);
            client.Dispose();
        }
    }
4

1 回答 1

0

您永远不应该(必须)指望常规程序流的异常。

当客户端关闭一个套接字时,服务器将收到一个 0 字节的数据包,并在您调用Receive. 这会导致您的 while 循环永远持续下去。您应该处理count0 的情况并将其视为常规的“客户端关闭的连接”。您提到的异常仅在客户端无法正常关闭时发生。

于 2012-04-25T18:08:08.720 回答