13

I have been searching since yesterday for a simpler solution to just ping a website & check if it returns 200 in Swift.

But all I'm finding are solutions in Objective C.

In Swift, I found some answers like

func pingHost(_ fullURL: String) {
        let url = URL(string: fullURL)

        let task = URLSession.shared.dataTask(with: url!) { _, response, _ in
            if let httpResponse = response as? HTTPURLResponse {
                print(httpResponse.statusCode)
            }
        }

        task.resume()
    }

But when I call it from some other function like

self.pingHost("https://www.google.com")

It gives weird errors like

2018-09-26 12:46:34.076938+0530 Net Alert[1608:52682] dnssd_clientstub ConnectToServer: connect()-> No of tries: 1
2018-09-26 12:46:35.082274+0530 Net Alert[1608:52682] dnssd_clientstub ConnectToServer: connect()-> No of tries: 2
2018-09-26 12:46:36.083497+0530 Net Alert[1608:52682] dnssd_clientstub ConnectToServer: connect()-> No of tries: 3
2018-09-26 12:46:37.083964+0530 Net Alert[1608:52682] dnssd_clientstub ConnectToServer: connect() failed path:/var/run/mDNSResponder Socket:5 Err:-1 Errno:1 Operation not permitted
2018-09-26 12:46:37.084497+0530 Net Alert[1608:52682] [] nw_resolver_create_dns_service_locked [C1] DNSServiceCreateDelegateConnection failed: ServiceNotRunning(-65563)
2018-09-26 12:46:37.087264+0530 Net Alert[1608:52682] TIC TCP Conn Failed [1:0x600003706e80]: 10:-72000 Err(-65563)
2018-09-26 12:46:37.088841+0530 Net Alert[1608:52673] Task <2B08658D-5DFA-48E9-A306-A47ED130DD1F>.<1> HTTP load failed (error code: -1003 [10:-72000])
2018-09-26 12:46:37.088990+0530 Net Alert[1608:52673] Task <2B08658D-5DFA-48E9-A306-A47ED130DD1F>.<1> finished with error - code: -1003

How do I just simply ping in Swift 4 & check if it returns 200?

Lorenzo
  • 3,293
  • 4
  • 29
  • 56
deadcoder0904
  • 7,232
  • 12
  • 66
  • 163
  • You find this helpful: https://stackoverflow.com/questions/46754478/cocoa-app-webview-not-loading-request – Pavan Sep 26 '18 at 07:30
  • @Pavan Don't want to load a Webview or anything. Just want to check if a website is up or not – deadcoder0904 Sep 26 '18 at 07:31
  • 1
    Yes and the answer was in there, you had to check both network options :) @deadcoder0904 – Pavan Sep 27 '18 at 12:03
  • Ohh yeah later checked it again & found out but it would've been more clear if you would've explained a bit more. Anyways thank you :) – deadcoder0904 Sep 28 '18 at 07:29

4 Answers4

25

If you're going to "ping" a website you'll want to use a HEAD request instead of a GET request. To see if a website is up you don't need the whole website, just the headers. It will save time and bandwidth:

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

if let url = URL(string: "https://apple.com") {
  var request = URLRequest(url: url)
  request.httpMethod = "HEAD"

  URLSession(configuration: .default)
    .dataTask(with: request) { (_, response, error) -> Void in
      guard error == nil else {
        print("Error:", error ?? "")
        return
      }

      guard (response as? HTTPURLResponse)?
        .statusCode == 200 else {
          print("down")
          return
      }

      print("up")
    }
    .resume()
}

(Omit the playground stuff if not running in a playground.)

  • To anyone seeing this answer in the future, I had some errors & to which solutions have been found & you can find them all [here](https://www.reddit.com/r/swift/comments/9j0f6z/ping_a_website_or_an_ip_address_or_check_if_a/?ref=share&ref_source=link) :) – deadcoder0904 Sep 27 '18 at 05:54
  • 2
    The errors are not due to this code, except perhaps in error handling. A badly-implemented web server might not handle the HEAD method properly and do all sorts of things such as resetting the connection or returning the wrong status. We can't account for all the weird ways that someone might handle a HTTP request, all we can do is code defensively against errors. –  Sep 27 '18 at 11:53
  • If you want to calculate ping time this won't cut it, as this approach actually waits for the full data response. The response object, as URLResponse, is unfortunately passed to the handler once the data is received. With that you calculate download time, not ping time. – pnizzle Apr 02 '20 at 06:22
  • 1
    Ping uses ICMP protocol of TCP/IP suite which is completely unrelated and low level to HTTP/HTTPS . Using a HEAD request to ping a host requires about 300ms (_in my case atleast_) is there a way I can ping a host using ICMP in swift? If I'm not wrong pinging throuh ICMP shall require only 30-50 ms. – SPS Aug 26 '20 at 17:00
  • @SPS you are correct. Did you find a solution to this? – Houman Aug 02 '21 at 20:33
7

I guess the problem is easy: You enabled App Sandbox but didn't check Outgoing Connections.

What about your pingHost method - it's completely correct. So I think only problem is in App Sandbox settings.

enter image description here

Anton Rodzik
  • 781
  • 4
  • 14
  • I'm trying to execute the above code in a command-line app I am building and I get no response at all. When I add in the sandbox capability as provided in your answer the program crashes. It works as expected from a Playground though regardless if I have sandbox turned on and allowing outgoing connections or not. This is the error reported by Xcode: Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) – SouthernYankee65 Dec 03 '21 at 19:02
3

If you're developing for MacOS Anton's answer is correct. If you're developing for iOS though you need to disable App Transport Security(ATS) if you're pinging a non-secure URL. In order to do that you need to set the NSAllowsArbitraryLoads to true under the NSAppTransportSecurity field in the Info.plist.

More information at: https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html - NSAppTransportSecurity

halil_g
  • 631
  • 6
  • 11
2

There is a third party library that you can use to achieve the same.

https://github.com/ankitthakur/SwiftPing

let pingInterval:TimeInterval = 3
let timeoutInterval:TimeInterval = 4
let configuration = PingConfiguration(pInterval:pingInterval, 
withTimeout:  timeoutInterval)

print(configuration)

SwiftPing.ping(host: "google.com", configuration: configuration, 
queue: DispatchQueue.main) { (ping, error) in
print("\(ping)")
print("\(error)")

}

SwiftPing.pingOnce(host: "google.com", configuration: 
configuration, 
queue: DispatchQueue.global()) { (response: PingResponse) in
print("\(response.duration)")
print("\(response.ipAddress)")
print("\(response.error)")

}

class PingResponse : NSObject {

public var identifier: UInt32

public var ipAddress: String?

public var sequenceNumber: Int64

public var duration: TimeInterval

public var error: NSError?

}

https://github.com/naptics/PlainPing

PlainPing.ping("www.google.com", withTimeout: 1.0, completionBlock: { 
(timeElapsed:Double?, error:Error?) in
if let latency = timeElapsed {
    self.pingResultLabel.text = "latency (ms): \(latency)"
}

if let error = error {
    print("error: \(error.localizedDescription)")
}
})
Lukas Würzburger
  • 6,543
  • 7
  • 41
  • 75
  • 2
    Links to external resources are encouraged, but please add context around the link so your fellow users will have some idea what it is and why it’s there. Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offline. – From [answer]. – Martin R Sep 26 '18 at 07:34
  • Found both but I was wondering if I could do it without an external library – deadcoder0904 Sep 26 '18 at 07:35
  • 1
    no offense I think its best practice to use code that is already tried and tested so using these libraries will save you a lot of time and effort – MOSES AFONSO Sep 26 '18 at 08:42
  • yes I do that too a lot since I come from JS world so used to NPM. but in swift it takes a lot of efforts to install it with Carthage. the reasoning for this was its not well maintained. anyways thanks. I'll try it if other solutions don't work :) – deadcoder0904 Sep 26 '18 at 09:23
  • 1
    @deadcoder0904 yes i completely forgot about NSAppTransportSecurity – MOSES AFONSO Sep 26 '18 at 09:27