Как отправить ответ после прочтения запроса из браузера с Socket? (Я использую SwiftSocket) - PullRequest
7 голосов
/ 21 января 2020

Я новичок в этой сети в iOS, поэтому не очень хорошо знаю все концепции, и я делаю приложение, которое позволяет отображать данные в браузере на устройстве, для этого я создаю сокет -порт и с использованием SwiftSocket library

override func viewDidLoad() {
    super.viewDidLoad()
    let ip = String(getAddress(for: .wifi)!)
    self.host = ip
    print("Getting IP address of wifi\n\(self.host)\n")
    self.selfserver()
}

Я думаю, что следующая функция selfserver() инициализирует сервер и ожидает подключения клиента

func selfserver()
{
    let server = TCPServer(address: self.host, port: Int32(port))
    switch server.listen() {
    case .success:
        while true {
            if let client2 = server.accept() {
                print("CLIENT ACCEPTED ....")
                 self.startconnection(senderclient: client2)
            } else {
                print("accept error")
            }
        }
    case .failure(let error):
        print(error)
    }
}

Когда клиент попытается подключиться после будет вызвана функция senderclient(senderclient: TCPClient), и в ответе я отправляю файл index.html, который сохраняется в htmlfileURL ключе Userdefaults

func startconnection(senderclient: TCPClient) {
    print("CLIENT ADD\n\(senderclient.address)\n")
    let filePath = UserDefaults.standard.url(forKey: "htmlfileURL")
    // Converting `index.html` in bytes to send
    var bytes = [UInt8]()
    if let data = NSData(contentsOfFile: filePath!.path) {
        var buffer = [UInt8](repeating: 0, count: data.length)
        data.getBytes(&buffer, length: data.length)
        bytes = buffer
        }

    senderclient.send(string: "HTTP/1.1 200 OK\n" +
        "Content-Length: \(bytes.count)\n" +
        "Connection: close\n" +
        "Content-Type: text/html\n" +
        "\n")
    switch senderclient.send(data: bytes) {
    case .success:
        let data = senderclient.read(1024*10)
        if let d = data {
            if let str = String(bytes: d, encoding: .utf8) {
                print("STR\n\(str)\n")
                // If I'm not wrong Here I should get the response 
            }
        }

    case .failure(let erro):
        print(erro)
    }
}

Моя проблема - это я я получаю все заголовки запросов и после фильтрации я также получаю, какие filename и content-type требует заголовок запроса, но я не знаю, как отправить этот файл после получения и чтения заголовка запроса в ответ.

enter image description here

Как вы можете видеть на скриншоте выше В области консоли вы можете видеть, что я получаю запрос файла styles.afcc5f0641cf44266b1b.css. ..Я просто не знаю, как отправить этот файл в браузер en он запрашивает (у меня полный путь к файлу)

Спасибо

Ответы [ 2 ]

4 голосов
/ 29 января 2020

После недельного изучения и изучения моих знаний я внес изменения, которые все еще не идеальны, но наиболее близки к желаемому ответу (и я публикую его с объяснением, чтобы он мог быть полезен для других)

ПРИМЕЧАНИЕ: - Я все еще ищу правильный ответ, который может быть очень полезен для всех, поскольку Socket в Swift - довольно сложная концепция для реализации !!!

//Iniiating Two variable which are initially empty to check if the loop is running first time
var loopablestring = String()
var loopableExtension = String()
//which was necessary here because otherwise only 'index.html' file will be sent in response to every request header    

//MARK:- Start connection with Client Socket Function
func startconnection(senderclient: TCPClient) {

    let filePath = Bundle.main.resourceURL
    var FilePath = String()
    var FileBytes = [Byte]()
    var ContType = String()

    //Initially this code will be called
    if self.loopablestring == "" {
        FilePath = filePath!.appendingPathComponent("index.html").path
        FileBytes = self.getBytesFromFile(fromPath: FilePath)
        self.loopableExtension = "html"
        ContType = self.getMimeType(file: self.loopableExtension)
    } else {
        FilePath = filePath!.appendingPathComponent(loopablestring).path
        FileBytes = self.getBytesFromFile(fromPath: FilePath)
        ContType = self.getMimeType(file: self.loopableExtension)
    }
    //sending requested file(if any or sending 'index.html')
    senderclient.send(string: "HTTP/1.1 200 OK\n" +
        "Content-Length: \(FileBytes.count)\n" +
        "Connection: close\n" +
        "Content-Type: \(ContType)\n" +
        "\n")

    print("Sending File Of Which Content-Type\t\(ContType)\n And Path\t\(FilePath)\nAnd Pure File Name\t\(loopablestring)\nWith Extension\t\(loopableExtension)\n")

    switch senderclient.send(data: FileBytes) {
    case .success:
        //print("SUCCESS")
        if let responseBytes = senderclient.read(1024*10) {
            let responseString = String(bytes: responseBytes, encoding: .utf8)!
            print("\nRespons String which contains Headers\n\(responseString)\n\n")

            let HeaderLines = responseString.components(separatedBy: .newlines)[0]
            let separator = HeaderLines.components(separatedBy: .whitespaces)[1]
            //print("Only first line of the Header\n\(HeaderLines)\n\n")

            if separator != "/" {
            //If we don't get Empty or nil value in request header then this code will run

            let purefilename = separator.components(separatedBy: "/")[1]
            //print("Pure File Name filtered from Header's First Line \n\(purefilename)\n")

                print("ALLOCATED FILE \n\(purefilename)\n")

                //giving that two variable values so in next loop's it won't go in `if self.loopablestring == ""` condition
                self.loopablestring = purefilename
                self.loopableExtension = self.getMimeType(file: separator)
                //giving that two variable values so in next loop's it won't go in `if self.loopablestring == ""` condition
            } else {
                print("CAME HERE to be closed")
            }
        }

    case .failure(let error):
        print("FAILED because of \(error)")
    }
    print(" \t\t AFTER THE LOOP \n\n\n")
    senderclient.close()
}

//To return Content Type to Browser (In response Header)
func getContentType(filename: String) -> String {
    do {
        if filename == "js" {
            return "application/javascript"
        } else if filename == "html" {
            return "text/html"
        } else if filename == "css" {
            return "text/css"
        } else if filename == "ico" || filename == "png" || filename == "PNG" || filename == "jpg"  || filename == "JPG" || filename == "jpeg" || filename == "JPEG" {
            return "image/png"
        } else {
            return "text/html"
        }
    } catch {
        print("Something is Wrong!!")
    }
}

//TO Get Extension without (.)DOT
func getMimeType(file: String) -> String {
    let ext = file.components(separatedBy: ".")
    //print("all extensions\n\(ext)\n")
    return ext.last!
}

После реализации приведенного выше кода я могу получить все заголовки запроса и отправить ответ, но осталась только одна проблема: (см. Скриншот ниже)

enter image description here

Теперь, как вы можете видеть на картинке, я могу прочитать весь заголовок ответа и отправляю запрошенные файлы тоже Но проблема (из-за l oop или я не знаю, что) - файл ответа, который я отправляю, идет в следующем запросе вместо текущего заголовка запроса

ex:

Показывает нулевые данные в первом запрошенном файле и данные / файл Ле я отправляю для первого styles.afcc5f0641cf44266b1b.css идет в следующем (втором) запрошенном заголовке runtime.26209474bfa8dc87a77c.js, и из-за этой ошибки мой последний файл favicon.ico даже не отправляется

Надеюсь, это поможет или кто-то мне помогает;)

0 голосов
/ 27 января 2020

ваш экземпляр создания TCPServer, который в действительности существует только внутри функции самообслуживания. Когда функция самообслуживания вернется, ее больше не будет !

сосредоточиться на том факте, что при запуске startconnection () не выполняется ни один экземпляр TCPServer, что означает отсутствие ответа от Это. В качестве первого шага верните его экземпляр из

selfserver()->TCPsever { ... return server  } 

и присвойте результат какому-либо свойству в вашем экземпляре View, чтобы расширить его livespan

...