【问题标题】:How to serve a remote file (taken from a remote SMB server) to certain requests如何为某些请求提供远程文件(取自远程 SMB 服务器)
【发布时间】:2016-01-16 06:48:41
【问题描述】:

当某些请求到达服务器(在移动应用程序上运行的服务器)时,我正在尝试提供视频文件作为响应。 eg:有人去http://mylocalip:8080/video,我想为他提供视频。

此视频文件可以存储在本地,也可以存储在外部。我开始尝试提供位于 SMB 服务器上的文件,因此我尝试使用此代码从服务器获取文件并返回它(我知道它正在等待读取整个文件而不是读取和发送块,但应该可以工作对吧?):

webServer.addDefaultHandlerForMethod("GET", requestClass: GCDWebServerRequest.self, processBlock: {request in
            print("########\n########Request: \(request)")
            let webrequested:GCDWebServerRequest = request;
            let urlcita:String = String(webrequested.URL)
            print("URL of requests\(urlcita)")
            if urlcita.rangeOfString("videosmb") != nil{
                print("It's a video SMB request")

                //Test fake SMB file predefined. Read File using KxSMB

                let route:String = "smb://192.168.1.205/ServidorAH/video.avi";
                let extensFile:NSString = (route as NSString).pathExtension
                let contentype = GCDWebServerGetMimeTypeForExtension(extensFile as String);
                print("Content type MIME \(contentype)")


                //Open SMB file using KxSMB
                let authcredentials = KxSMBAuth.smbAuthWorkgroup("", username: "Guest", password: "");
                let provider = KxSMBProvider.sharedSmbProvider()!
                let archivoes = provider.fetchAtPath(route, auth: authcredentials)

                //Switch to manually end the reading when switched to true. In the future will send chunks of data until the end, instead of reading the whole file first.
                var interruptor:Bool = false

                //Response Stream block
                let responseStream: GCDWebServerStreamedResponse = GCDWebServerStreamedResponse(contentType: contentype, asyncStreamBlock: { completionBlock in

                    if (interruptor == true)
                    {
                        print("Test: End of reading")
                        completionBlock(NSData(), nil);
                    }

                    if archivoes!.isKindOfClass(NSError){
                        //It can not find the file, SMB error, so empty NSDATA to completion block
                        let errorcito:NSError = archivoes as! NSError
                        print("Error obteniendo archivo SMB: \(errorcito.localizedDescription)");
                        completionBlock(NSData(), nil);
                    }else{
                        print("Archivo SMB adecuado \(archivoes)")
                        let datos:NSData = archivoes!.readDataToEndOfFile()
                        //Print lenght of data (to check the size of the file)
                        print("Data lenght \(datos.length)")
                        //Set switch to true, so the next call will send an empty daya completion block
                        interruptor = true
                        //Send data chunk (in this case everything)
                        completionBlock(datos, nil);
                    }

                })
                return responseStream


            }else{
                //Default response
                return GCDWebServerDataResponse(HTML:"<html><body><p>Hello World<br></p></body></html>")
 }

但是,我无法让它工作。我总是遇到管道损坏错误,访问网络服务器的网络播放器(也从 mac 和 iOS 浏览)不播放任何内容。我还尝试使用嵌入式 iOS 播放器来记录响应(KxMovie)。我得到这样的东西:

[DEBUG] Did open connection on socket 19
[DEBUG] Connection received 177 bytes on socket 19
[DEBUG] Connection on socket 19 preflighting request "GET /videosmb" with 177 bytes body
[DEBUG] Connection on socket 19 processing request "GET /videosmb" with 177 bytes body
[DEBUG] Did connect
[DEBUG] Did start background task
[DEBUG] Connection sent 175 bytes on socket 19
...

从应用程序内部使用本地播放器 (KxMovie),这里似乎正在读取文件头,它会获取正确的文件大小和视频尺寸。但是它不播放,最后说它到达了视频的结尾(没有播放)。紧接着,WebServer 显示错误:

...       

[ERROR] Error while writing to socket 19: Broken pipe (32)
[DEBUG] Did close connection on socket 19
[VERBOSE] [fe80::cd0:28cd:3a37:b871%en1:8080] fe80::cd0:28cd:3a37:b871%en1:50109 200 "GET /videosmb" (177 | 175)
[DEBUG] Did disconnect
[DEBUG] Did end background task

鉴于这是我第一次与 SMB 服务器打交道,我认为我可能在 SMB 部分做错了什么,所以我决定采用一种简化的方法来进行测试。 这次我尝试提供存储在远程网络服务器(不是 SMB)上的简单 mp4 文件。它也没有用。 最后我尝试提供一个包含在应用程序主包中的本地文件,同样的事情发生了:什么都没有。代码如下:

webServer.addDefaultHandlerForMethod("GET", requestClass: GCDWebServerRequest.self, processBlock: {request in
       print("########\n########Request: \(request)")
       let webrequested:GCDWebServerRequest = request;
       let url:String = String(webrequested.URL)
       print("URL of request: \(url)")
       if url.rangeOfString("video") != nil{
            print("It's a video request")

            let rutalocalita = (NSBundle.mainBundle()).pathForResource("video", ofType: "avi")
            let datos = NSData(contentsOfFile: rutalocalita!)!
            print("video size: \(datos.length)")
            return GCDWebServerDataResponse(data: datos, contentType: "video/avi")

        }else{
           //Default Response: Simple web
           return GCDWebServerDataResponse(HTML:"<html><body><p>Hello World<br></p></body></html>")
        }
})

这是日志的样子:

[DEBUG] Did open connection on socket 19
[DEBUG] Connection received 177 bytes on socket 19
[DEBUG] Connection on socket 19 preflighting request "GET /video" with 177 bytes body
[DEBUG] Connection on socket 19 processing request "GET /video" with 177 bytes body
[DEBUG] Did connect
[DEBUG] Did start background task
[myCUSTOMDebug] Read 13584902 b. I'm going to send the response back to the request.
[DEBUG] Connection sent 173 bytes on socket 19
...

我在应用内使用的本地 Playing 来跟踪响应,能够读取如下内容:

header='HTTP/1.1 200 OK'
2015-10-17 17:51:41.571 videotvtest[262:14252] http_code=200
2015-10-17 17:51:41.571 videotvtest[262:14252] header='Cache-Control: no-cache'
2015-10-17 17:51:41.571 videotvtest[262:14252] header='Content-Length: 13584902'
2015-10-17 17:51:41.572 videotvtest[262:14252] header='Content-Type: video/avi'
2015-10-17 17:51:41.572 videotvtest[262:14252] header='Connection: Close'
2015-10-17 17:51:41.573 videotvtest[262:14252] header='Server: GCDWebServer'

...
[ERROR] Error while writing to socket 19: Broken pipe (32)
[DEBUG] Did close connection on socket 19
[VERBOSE] [fe80::cd0:28cd:3a37:b871%en1:8080] fe80::cd0:28cd:3a37:b871%en1:50155 200 "GET /video" (177 | 173)
netbios_ns_send_name_query, name query sent for '*'.
[DEBUG] Did disconnect
[DEBUG] Did end background task

为此,我正在使用 tvOS 和 Xcode 7,但我想如果我能够显示常规的 HTML 响应应该没问题...所以我确定我错过了什么,或者也许我在安装 WebServer 时错过了一些框架(我没有使用 pod)? 提前致谢

【问题讨论】:

  • SMB、视频文件、手表操作系统、网络服务器之间的移动部件太多...您应该首先从 Mac 应用程序或 iPhone 应用程序提供常规本地文件,然后是视频文件,然后是 SMB,最后转向观看操作系统。
  • 您好 Pol,感谢您的回复。但是,在我的代码上与 watch OS 没有任何关系!这里的主要问题,经过更多测试,似乎与内容范围有关,因为我能够播放每个测试的文件(本地、smb、远程等)桌面谷歌浏览器完美无瑕!但是,当我尝试 iOS 播放器或 OS X Safari 时,它失败了......告诉我一些关于“无法加载资源:插件模块管理”在开发者控制台中的信息。我知道如果它们存储在本地,则可以提供某种范围文件......但是第 3 方呢?我应该先在本地下载它们吗?
  • 你应该更新这个问题的标题,因为它太笼统了,也不是一个真正的问题。
  • 嗨,请原谅我,因为它与您的问题无关,但是您对 KxSMB 做了哪些更改以使其能够在 swift 上构建? @eiprol

标签: ios swift video tvos gcdwebserver


【解决方案1】:

如果你想提供一个可以使用视频标签在浏览器中播放的视频文件,至少在 Chrome 和 Safari 上,你需要实现 HTTP 范围请求。

如果你使用GCDWebServerFileResponse,GCDWebServer 会自动实现范围支持。如果您使用其他类型的响应,则需要根据传入的GCDWebServerRequestbyteRange 属性自己实现它。您应该从GCDWebServerFileResponse.m 复制粘贴逻辑。

【讨论】:

  • 我想类似的方法是这样的;但是,由于我正在尝试读取外部/远程文件(不是存储在与 GCDWebServer 相同的设备上)并将它们作为对某些请求的响应,因此我不能在不更改它的情况下使用该类型(提供路径, 正如 GCDWebServerFileResponse 所做的那样, 为存储在 SMB 服务器上的文件提供服务是没有用的, 我应该提供一种方法来异步读取该文件 (也许) 并返回 NSData。也许我应该在 GCDWebServerFileResponse (用于字节范围)之间进行混合, GCDWebServerStreamedResponse(异步读取)
猜你喜欢
  • 1970-01-01
  • 2020-10-01
  • 2012-06-15
  • 1970-01-01
  • 2022-11-21
  • 2023-03-26
  • 2015-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多