在 Swift 中实施 FTP 文件传输 (STOR)?
Implementing FTP file transfer (STOR) in Swift?
我正在开发用 Swift 编写的客户端 iOS 应用程序,它允许用户在 FTP 上传输文件服务器。我知道 Apple 提供 API 来执行此操作,但自 2016 年以来它们已被弃用,我需要一个替代方案。我也知道 FTP 不安全,但我必须这样做。我的目标是通过服务器打开一个套接字并向它发送命令以传输文件。我正在使用 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()
我观察到只有当我终止应用程序时文件才会完全传输。有什么想法吗?
您必须解析 PASV
响应 (passiveModeAnswer
)。并连接到提供的 IP 地址和端口并将文件内容发送到新连接。
我正在开发用 Swift 编写的客户端 iOS 应用程序,它允许用户在 FTP 上传输文件服务器。我知道 Apple 提供 API 来执行此操作,但自 2016 年以来它们已被弃用,我需要一个替代方案。我也知道 FTP 不安全,但我必须这样做。我的目标是通过服务器打开一个套接字并向它发送命令以传输文件。我正在使用 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()
我观察到只有当我终止应用程序时文件才会完全传输。有什么想法吗?
您必须解析 PASV
响应 (passiveModeAnswer
)。并连接到提供的 IP 地址和端口并将文件内容发送到新连接。