WebWost WebWostbeta

Проверка доступности сайта с помощью Golang

Проверка доступности сайта, используя Golang.

Al-Sher

Всем привет. Уже давно я пытаюсь изучить Golang, ну вот и решил написать небольшую программу для автоматической проверки сайтов из списка.

Внимание!Использование ПО разрешается лишь с вашем собственным сайтом!

Весь код программы на GitHub

Подготовка.

Для начала необходимо установить Golang. Думаю это не вызовет проблем, достаточно скачать инсталятор с официального сайта и запустить его. Но, если вдруг, это вызвало сложности, то можно почитать инструкцию. В программе используются лишь стандартные пакеты, поэтому всё должно работать и без установки доп. пакетов.

Код.

Вся программа поделена 4 функции:

Итак, начнем с сначала. А в начале нам необходимо объявить название пакета. Так как мы пишем приложение, то название пакета должно быть main: package main Далее импортируем необходимые пакеты и объявляем наши переменные:

import (
    "net/http"
    "net/url"
    "fmt"
    "io/ioutil"
    "os"
    "strings"
    "time"
    "strconv"
)

var timer int = 1
var proxy string = ""

Не буду вдаваться в подробности данных пакетов. А вот переменные... Переменная timer предназначена для установки таймера. То есть время, спустя которое программа заходит на сайт. По-умолчанию стоит 1. Переменная proxy предназначена для работы приложения через прокси. Позволит проверять внутренние ресурсы

Ну и затроним еще функцию main, то есть нашу главную функцию:

func main() {
    sites := getSitesFromFile("sites.txt")
    getParamsFromArgs()
    if timer > 1 {
        fmt.Println("use timer: ", timer)
    }
    if proxy != "" {
        fmt.Println("use proxy: ", proxy)
    }
    ch := make(chan byte, 1)
    for _, site := range sites {
        go func (site string) {
            for {
                testSite(site)
                time.Sleep(time.Duration(timer) * time.Second)
            }
            ch <- 1
        }(site)
    }
    <-ch
}

Итак, мы объявили функцию. В переменную sites мы сохраняем все необходимые нам дя проверки сайты, которые лежат в файле sites.txt: sites := getSitesFromFile("sites.txt") Далее мы вызываем вспомогательную функцию getParamsFromArgs: getParamsFromArgs() Если время таймера больше 1, то мы используем не стандартное время, а значит передали программе время таймера. Время, кстати, в секундах, но об этом позже. Так же проверяем использование прокси:

    if timer > 1 {
        fmt.Println("use timer: ", timer)
    }
    if proxy != "" {
        fmt.Println("use proxy: ", proxy)
    }

Так же создаем канал ch для того, чтобы процесс main не завершался. Это позволит выводить сообщения в консоль: ch := make(chan byte, 1) Итак, проходимся по массиву наших сайтов. В переменной site хранится один адрес: for _, site := range sites { Реализуем многопоточность благодаря вызову анонимной функции через go. В эту функцию передаем значение переменной site: go func (site string) { В данной функции мы осуществляем бесконечный цикл. По завершению мы передаем очереди, что всё готово. Так же именно тут вызывается функция testSite, которой мы передаем адрес сайта. А еще можно заметить и наш таймер:

            for {
                testSite(site)
                time.Sleep(time.Duration(timer) * time.Second)
            }

После каждого выполнения testSite мы отправляем поток в "сон" на определенное время. Именно тут и указано, что мы используем секунды, благодаря умножению на time.Second: time.Duration(timer) * time.Second Далее мы используем наш канал ch, передавая в него единицу: ch <- 1 Вызываем нашу анонимную функцию с параметром site: }(site) Выбрасываем в пустоту значение канала ch: <-ch.

Функция getSitesFromFile.

Далее мы рассматриваем getSitesFromFile, то есть получение сайтов из файла:

func getSitesFromFile(namefile string) []string {
    data, err := ioutil.ReadFile(namefile)
    if err != nil {
        fmt.Println("error: ", err)
        os.Exit(2)
    }
    result := string(data)

    test := strings.Split(result, "\r\n")
    return test
}

В ней мы передаем название нашего файла и указываем, что вернется массив строк: func getSitesFromFile(namefile string) []string { Далее мы загружаем содержимое файла в переменную data, а так же ошибку в err: data, err := ioutil.ReadFile(namefile) Проверяем на ошибки:

    if err != nil {
        fmt.Println("error: ", err)
        os.Exit(2)
    }

Если есть ошибки, то выводим ошибку и завершаем программу. Далее переводим содержимое файла из байт в строку: result := string(data) Разделяем строку по символам \r\n, то есть по пропуску строки: test := strings.Split(result, "\r\n") И возвращаем результат: return test

Функция getParamsFromArgs.

Как я говорил, мы принимаем дополнительные параметры из командой строки. Вот эта функция:

func getParamsFromArgs() {
    if len(os.Args) > 1 {
        for i, _ := range os.Args {
            if os.Args[i] == "proxy" {
                i++
                proxy = os.Args[i]
            }
            if os.Args[i] == "timer" {
                i++
                timer, _ = strconv.Atoi(os.Args[i])
            }
        }
    }
}

В ней мы проверяем содержимое аргументов os.Args: if len(os.Args) > 1 { Первый элемент всегда название исполняемого файла, поэтому используем проверку на больше 1. Далее проходимся циклом по данным аргументам: for i, _ := range os.Args { Если находим необходимые нам параметры, то следующий параметр записываем в нужные места. Легко можно расширить возможности...

Функция testSite.

И вот мы дошли до самой интересной функции - testSite:

func testSite(u string) bool {
    if u == "" {
        return false
    }
    client := http.Client{}
    if proxy != "" {
        proxyUrl, _ := url.Parse(proxy)
        client = http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl)}}
    }
    req, _ := http.NewRequest("GET", u, nil)
    req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT x.y; Win64; x64; rv:10.0) Gecko/20100101 Firefox/10.0")
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("error: ", err)
        return false
    } 
    _, err := ioutil.ReadAll(resp.Body)
    if err == nil {
        if resp.StatusCode == 200 {
            fmt.Println(u + ": " + "ok")
        } else {
            fmt.Println("Site ", u, " returned error code: ", resp.StatusCode)   
        }
    }
    defer resp.Body.Close()
    return true
}

Мы передаем данной функции необходимый url адес. Сама функция возвращает bool'евое значение: func testSite(u string) bool { Проверяем не пустой ли url адрес:

    if u == "" {
        return false
    }

Создаем http клиента: client := http.Client{} Проверяем прокси. Если он имеется, то настраиваем наш клиент:

    if proxy != "" {
        proxyUrl, _ := url.Parse(proxy)
        client = http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl)}}
    }

Создаем переменную Request. Она будет содержать все необходимые параметры, передаваемые клиенту, в том числе и метод, и url адрес: req, _ := http.NewRequest("GET", u, nil) Задаем заголовок браузера: req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT x.y; Win64; x64; rv:10.0) Gecko/20100101 Firefox/10.0") И исполняем запрос клиентом: resp, err := client.Do(req) Функция вернет нам ответ сервера(resp) и ошибку(err). Проверяем на наличие ошибки:

    if err != nil {
        fmt.Println("error: ", err)
        return false
    } 

Проверяем ошибки чтения из Body:

    _, err := ioutil.ReadAll(resp.Body)
    if err == nil {

Если ошибок нет, то проверяем статус ответа:

        if resp.StatusCode == 200 {
            fmt.Println(u + ": " + "ok")
        } else {
            fmt.Println("Site ", u, " returned error code: ", resp.StatusCode)   
        }

Закрываем Body после того, как он нам не нужен:

defer resp.Body.Close()

И возвращаем true: return true.

Заключение.

Вот вам простенькая программа для проверки ваших сайтов на доступность, которую можно собрать как под linux, так и под windows :) Спасибо за внимание, надеюсь она послужит для достойных целей!

0 Комментариев

Новый комментарий