【发布时间】:2021-06-02 13:39:59
【问题描述】:
我正在开发一个用 Swift 编写的客户端 iOS 应用,它允许用户在 FTP 服务器 上传输文件。我知道 Apple 提供了 API 来执行此操作,但它们自 2016 年以来已被弃用,我需要一个替代方案。我也知道 FTP 不安全,但我必须这样做。我的目标是通过服务器打开一个 Socket 并向它发送命令以传输文件。我正在使用BlueSocket,但我无法得到它。这是我的代码:
do {
let socket = try Socket.create()
try socket.connect(to: "127.0.0.1", port: 21)
let answer = try socket.readString()
print(answer!)
try socket.write(from: "USER test\r\n")
let userAnswer = try socket.readString()
print(userAnswer!)
try socket.write(from: "PASS 0000\r\n")
let passwordAnswer = try socket.readString()
print(passwordAnswer!)
try socket.write(from: "PASV\r\n")
let passiveModeAnswer = try socket.readString()
print(passiveModeAnswer!)
try socket.write(from: "STOR myFile.txt\r\n")
let storAnswer = try socket.readString()
print(storAnswer!)
/* CODE FOR SENDING FILE BELOW */
} catch let error as NSError {
print(error.debugDescription)
}
我目前正在本地服务器上工作,并且登录成功。服务器已准备好接受数据。我在控制台中看到了这个:
150 Ok to receive data.
这是我用来发送文件的代码:
guard let path = Bundle.main.path(forResource: "myFile", ofType: "txt"),
let fileInputStream = InputStream(fileAtPath: path)
else {
return
}
fileInputStream.open()
var buffer = [UInt8](repeating: 0, count: 1024)
var bytesRead = 0
var fileData = Data()
while fileInputStream.hasBytesAvailable {
bytesRead = fileInputStream.read(&buffer, maxLength: buffer.count)
fileData.append(buffer, count: bytesRead)
}
try socket.write(from: fileData)
let fileAnswer = try socket.readString()
print(fileAnswer!)
fileInputStream.close()
socket.close()
执行后,我在本地服务器中看到“myFile.txt”,但它是空的。原始文件存储在 Xcode 中:它是一个 13 字节的文件(一个简单的文本文件)。我看到一个断点,bytesRead 更改为 13 并且 fileData 被重视。在try socket.write(from: fileData) 指令之后,我没有收到来自套接字的任何响应,但只有这个错误消息:Error code: -9982(0x-26FE), Interrupted system call。有什么遗漏或错误吗?我在实现目标方面做得很好吗?
正如 Martin 所说,我已经解析了 PASV 答案的结果,代码如下:
guard let path = Bundle.main.path(forResource: "myFile", ofType: "txt"),
let fileInputStream = InputStream(fileAtPath: path)
else {
return
}
fileInputStream.open()
guard let pasvAnswer = passiveModeAnswer else {
return
}
var editedAnswer = String(pasvAnswer.dropFirst(26))
editedAnswer = editedAnswer.replacingOccurrences(of: ")", with: "")
editedAnswer = editedAnswer.replacingOccurrences(of: "(", with: "")
editedAnswer = editedAnswer.replacingOccurrences(of: ",", with: ".")
editedAnswer = String(editedAnswer.dropLast())
let cmps = editedAnswer.components(separatedBy: ".")
let dataHost = cmps[0] + "." + cmps[1] + "." + cmps[2] + "." + cmps[3]
let dataPort = ((Int(cmps[4]))!<<8) + Int(cmps[5])!
print("dataHost: \(dataHost), dataPort: \(dataPort)")
try socket.write(from: "STOR myFile.txt\r\n")
let storAnswer = try socket.readString()
print(storAnswer!)
let dataSocket = try Socket.create()
try dataSocket.connect(to: dataHost, port: Int32(dataPort))
var buffer = [UInt8](repeating: 0, count: 1024)
var bytesRead = 0
var fileData = Data()
while fileInputStream.hasBytesAvailable {
bytesRead = fileInputStream.read(&buffer, maxLength: buffer.count)
fileData.append(buffer, count: bytesRead)
}
try dataSocket.write(from: fileData)
let fileAnswer = try dataSocket.readString()
print(fileAnswer!)
fileInputStream.close()
dataSocket.close()
socket.close()
我观察到该文件仅在我终止应用程序时才完全传输。有什么想法吗?
【问题讨论】: