今天在中午吃饭的时候,和同事日常闲聊。

事情还要回到今天上午,领导布置了一个任务,说要让我们下星期二给电力市场业务组的人员介绍一下国网云的各个组件的使用。因为在这之前都是我来协调国网云的安装人员(其实就是国网下面的一个分公司)过来到我们机房安装国网云的各个组件,所以各种使用手册和资料都在我这里保存着。然后我就正好可以使用FastDFS分享文件了 ,同事们想要下载文件也必须使用我这个软件了,嘻嘻。

在闲聊的过程中,一个同事说:要是一个人在下载的过程中,另外一个人删除了这个文件会怎么样?确实,这种并发的问题,我在编程的时候一般也不会马上去想,都是本着最小产品的原则,先把基本功能实现了,再来慢慢优化更新,所以这种问题就不会去考虑到。其实这也暴露了我在编程中的一个缺陷,就是不考虑并发问题,还是单线程思路。既然他提出了这样一个好问题,那么我也没有理由不去思考了。

不过在我和另外一个同事测试的过程中,并没有发现异常。我在点击下载的同时,另外一位同事点击删除,两个操作都没有报错。似乎FastDFS已经帮我考虑了这个并发问题。

我起初怀疑是不是在我删除文件的时候,FastDFS看到还有一个进程在调用它就不会在本地真正删除,先“缓存”一下。可是在我登录服务器上文件实际存储的位置时,发现只要我点了删除的按钮,也就是向FastDFS服务器端发送了删除的命令之后,在存储位置确实发现文件已经删除了。但是另外一个下载的进程还在进行中,而且还处于从FastDFS获取流的过程中。

贴上下载的代码片段:

    logger.info("开始从FastDFS获取流......");
    @Cleanup InputStream input = FastDFSClient.downFile(groupName, remoteFileName);
    logger.info("从FastDFS获取流成功!!!");
    int index;
    byte[] bytes = new byte[1024];
    @Cleanup ServletOutputStream outputStream = null;
    try {
         response.setHeader("Content-type", "application/octet-stream");
         response.setHeader("Content-disposition", "attachment;fileName=" + new String(fileName.getBytes(), "ISO-8859-1"));
         outputStream = response.getOutputStream();
         //浏览器真正响应是从这里开始
         logger.info("Join download queue...");
         while ((index = input.read(bytes)) != -1) {
             outputStream.write(bytes, 0, index);
             outputStream.flush();
         }
         logger.info("下载成功!!!");
        } catch (IOException e) {
          logger.info("下载失败!!!");
          e.printStackTrace();
       }

这就让我有点摸不着头脑了,下一步决定深入看一下FastDFS的源码,看看它是怎么解决这个问题的。但是想到它是C++写的,我眼泪掉下来。

在测试过程中,还发现了一个新异常,就是Broken pipe。这个异常产生的原因常是当TCP连接的管道读端没有在读,而管道的写端继续有线程在写,就会造成管道中断。

好了,办公室没人了,要下班了。。。



技术分享     

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!