Websocket 文件上传速度问题(Java websocket API 和 Javascript)

Posted

技术标签:

【中文标题】Websocket 文件上传速度问题(Java websocket API 和 Javascript)【英文标题】:Websocket File upload speed issue (Java websocket API and Javascript) 【发布时间】:2014-03-17 18:41:51 【问题描述】:

我勉强做了websocket文件上传功能。但上传速度似乎很慢。我为 websocket 服务器使用了 Java API,为客户端使用了 javascript

服务器:

package websocket;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/receive/fileserver")
public class FileServer 
    static File uploadedFile = null;
    static String fileName = null;
    static FileOutputStream fos = null;
    final static String filePath="d:/download/";
    int fCount=0;

    @OnOpen
    public void open(Session session, EndpointConfig conf) 
        System.out.println("Websocket server open");
    

    @OnMessage
    public void processUpload(ByteBuffer msg, boolean last, Session session) 
        System.out.println("Binary Data: " + fCount + ", Capacity: "+ msg.capacity());      
        fCount++;
        while(msg.hasRemaining())          
            try 
                fos.write(msg.get());
             catch (IOException e)                
                e.printStackTrace();
            
               
    

    @OnMessage
    public void message(Session session, String msg) 
        System.out.println("got msg: " + msg);
        if(!msg.equals("end")) 
            fileName=msg.substring(msg.indexOf(':')+1);
            uploadedFile = new File(filePath+fileName);
            try 
                fos = new FileOutputStream(uploadedFile);
             catch (FileNotFoundException e)      
                e.printStackTrace();
            
        else 
            try 
                fos.flush();
                fos.close();                
             catch (IOException e)        
                e.printStackTrace();
            
        
    

    @OnClose
    public void close(Session session, CloseReason reason) 
        System.out.println("socket closed: "+ reason.getReasonPhrase());
    

    @OnError
    public void error(Session session, Throwable t) 
        t.printStackTrace();

    

客户:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Chat</title>
</head>
<body>
    <h2>File Upload</h2>
    Select file
    <input type="file" id="filename" />
    <br>
    <input type="button" value="Connect" onclick="connectChatServer()" />
    <br>
    <input type="button" value="Upload" onclick="sendFile()" />
    <script>
        var ws;

        function connectChatServer() 
            ws = new WebSocket(
                    "ws://localhost:8080/MyHomePage/receive/fileserver");

            ws.binaryType = "arraybuffer";
            ws.onopen = function() 
                alert("Connected.")
            ;

            ws.onmessage = function(evt) 
                alert(evt.msg);
            ;

            ws.onclose = function() 
                alert("Connection is closed...");
            ;
            ws.onerror = function(e) 
                alert(e.msg);
            

        


        function sendFile() 
            var file = document.getElementById('filename').files[0];
            ws.send('filename:'+file.name);
            var reader = new FileReader();
            var rawData = new ArrayBuffer();            

            var fStart = 0; //start byte
            var fEnd = 1024*1024; //packet size & end byte when slicing file.
            var fileFrag; //file fragment                       

            reader.loadend = function()            
                console.log('load end');
            

            reader.onload = function(e) 
                if(e.target.readyState == FileReader.DONE) 
                    rawData = e.target.result;              
                    //var blob = new Blob([rawData]);           
                    ws.send(rawData);   
                               
            

            fileFrag = file.slice(fStart, fEnd);
            reader.readAsArrayBuffer(fileFrag);         

            objRun = setInterval(function()                
                if (ws.bufferedAmount == 0)                    
                    if(reader.readyState == FileReader.DONE)                       
                        if(fStart<file.size)                           
                            fStart = fEnd + 1;
                            fEnd = fStart + 1024*1024;
                            fileFrag = file.slice(fStart, fEnd);
                            console.log('fileFrag Size: ' + fileFrag.size + 'Frag End: ' + fEnd);
                            reader.readAsArrayBuffer(fileFrag); 
                         else clearInterval(objRun);
                     //end of readyState
                 //end of ws.buffer
            , 5);//end of setInterval      
        //end of sendFile()    

    </script>
</body>
</html>

根据服务器端日志,分片数据大小为8K。我怎样才能增加这个?或者有什么办法可以提高上传速度?

提前致谢:)

【问题讨论】:

【参考方案1】:

尝试将setMaxBinaryMessageBufferSize() 设置为 1MB 到您的会话。不知道 javax 到底是什么,但是 jetty 并没有改变片段大小,但是速度却大大提高了。

【讨论】:

【参考方案2】:

会话对象有很多方法。其中一些是为了解决您的问题而引入的。

setMaxBinaryMessageBufferSize(int lenght) - 因为您的客户端似乎一次发送整个文件数据,服务器上的缓冲区无法处理该大小。

实际上,发送整个文件数据会使程序易受攻击并依赖于它处理的文件。这也不是一个好的性能决定。因为你提到你的过程很慢。一般来说,分配足够大的缓冲区大小以能够在内存中保存文件数据可能会降低性能,因为它可能会导致内存交换。

我会分段上传大文件。我使用一些套接字 API(不是 WebSocket API)来做到这一点,它的工作速度非常快。

还有一点。我注意到您对不同的消息类型使用了两种 OnMessage 方法。但是,我认为你需要在这种情况下使用 MessageHandlers,否则你的程序,正如你所报告的,可能会混淆哪个消息去哪个方法。

请看这个例子 https://github.com/nickytd/websocket-message-handlers-example/blob/master/websocket.messagehandler.web/src/main/java/websocket/messagehandler/example/endpoints/FullEchoEndpoint.java

【讨论】:

我喜欢你用这个去哪里。在setMaxBinaryMessageBufferSize(int lenght) 上使用反引号表示代码,不要只提供链接答案,而是将链接中最相关的代码片段粘贴到您的答案中并解释它们,然后包含源链接。

以上是关于Websocket 文件上传速度问题(Java websocket API 和 Javascript)的主要内容,如果未能解决你的问题,请参考以下文章

java项目,我上传dbf文件,解析文件数据保存到数据库里,数据量太大,速度太慢

通过 WebSocket (BinaryWebSocketFrame) 和 Netty 上传文件

与 Servlet 相比,使用 Websocket 下载文件速度较慢

利用Java实现断点上传

如何通过 Websocket 协议处理 GraphQL 中的文件上传?

Java EE 7:如何将 EJB 注入 WebSocket ServerEndpoint?