Коллеги объясните балбесу, почему? код не работает
Так значит проблема вот в чем,решил я решил порефакторить функцию ,а переписал в итоге все покрасивше))) но чего-то не заводится. почему не могу понять))) Помогите))) и да вот репозиторий https://github.com/yuzameOne/cli_ip_range_creator/blob/main/main.go где все работает 3 горутины 2 канала (так что не пишите иди про горутины читай))))) проект учебный.... выеживаюсь хочу сделать как то по другому Ps.Заранее спасибо за ответ ))))
func main() {
fmt.Println("Start work")
start := time.Now()
// Get current working directory.
path, err := os.Getwd()
if err != nil {
fmt.Printf("Error getting current working directory: %v", err)
}
// Parse command line arguments.
var filePath, savePath string
flag.StringVar(&filePath, "ptf", "range_ip.txt", "Path to input file")
flag.StringVar(&savePath, "ptsf", "", "Path to save output file")
flag.Parse()
// Check for missing input file path argument.
if filePath == "" {
fmt.Println("Missing required argument: path to input file")
}
// Set default output file path if not provided.
if savePath == "" {
savePath = path + "/new_" + filePath
}
// Open input file.
inputFile, err := os.Open(filePath)
if err != nil {
fmt.Printf("Error opening input file: %v", err)
}
defer inputFile.Close()
// Open output file.
outputFile, err := os.OpenFile(savePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0755)
if err != nil {
fmt.Printf("Error opening output file: %v", err)
}
defer outputFile.Close()
// Create wait group.
var wg sync.WaitGroup
// Create input line scanner.
scanner := bufio.NewScanner(inputFile)
lineCount := 0
for scanner.Scan() {
lineCount++
}
for i := 0; i < lineCount; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for scanner.Scan() {
line := strings.TrimRight(scanner.Text(), "\n")
partsIP := strings.Split(line, "-")
firstIP := net.ParseIP(partsIP[0])
secondIP := net.ParseIP(partsIP[1])
firstIPOctets := firstIP.To4()
secondIPOctets := secondIP.To4()
if firstIPOctets[2] == secondIPOctets[2] && firstIPOctets[3] == secondIPOctets[3] {
return
}
if firstIPOctets[2] > secondIPOctets[2] {
for i := 0; i < 256; i++ {
outputFile.WriteString(fmt.Sprintf("%d.%d.%d.%d", firstIPOctets[0], firstIPOctets[1], firstIPOctets[2], i))
}
}
if firstIPOctets[2] == secondIPOctets[2] && firstIPOctets[3] != secondIPOctets[3] {
for i := 0; i < 256; i++ {
outputFile.WriteString(fmt.Sprintf("%d.%d.%d.%d", firstIPOctets[0], firstIPOctets[1], firstIPOctets[2], i))
}
}
if firstIPOctets[2] < secondIPOctets[2] {
for {
var ipresult string
for i := 0; i < 256; i++ {
outputFile.WriteString(fmt.Sprintf("%d.%d.%d.%d", firstIPOctets[0], firstIPOctets[1], firstIPOctets[2], i))
}
ipresult = fmt.Sprintf("%d.%d.%d.%d", firstIPOctets[0], firstIPOctets[1], firstIPOctets[2], 255)
if ipresult == partsIP[1] {
break
}
firstIPOctets[2] = firstIPOctets[2] + 1
}
}
}
}()
}
// Wait for all goroutines to complete.
wg.Wait()
duration := time.Since(start)
fmt.Printf("Time taken: %v, output file: %s\n", duration, savePath)
}
Ответы (1 шт):
Почему ваш код не работает. Удивительно, если бы он работал. Проблем более одной.
Сначала вы прочитываете весь файл, когда подсчитываете количество строк:
for scanner.Scan() { lineCount++ }Как следствие, сканер находится в конце файла, и следующее обращение к
scanner.Scanвернётfalse. Соответственно, все горутины, в которых вы поставили циклfor scanner.Scan() { }в этот цикл не заходят, так как метод возвращаетfalse.Теперь про горутины. Это вообще за гранью моего понимания.
- Во-первых, вы запускаете горутины по числу строк во входном файле. Зачем? Зачем вообще горутины, если вы последовательно читаете строку за строкой?
- Во-вторых, все горутины читают из одного источника -
scanner. То есть горутины наперегонки пытаются считать строка за строкой из объекта, который не является tread-safe. Результат такого параллельного чтения непредсказуем. - В-третьих, все горутины читают этот
scannerдо его исчерпания. То есть в случае небольших файлов одна горутина успеет до исчерпания своего кванта времени прочитать до конца весь файл (в предположении что scanner не пуст). - В-четвёртых, все горутины пишут в один и тот же файл, и при этом каждая горутина пишет идентичные данные. То есть у вас будет по несколько экземпляров одних и тех же строк.
Я предполагаю, что вы хотели напечатать все адреса, принадлежащие диапазону, но делать это нужно иначе.
Я бы сделал итератор адресов
// Iterates addresses from Start till End inclusive.
type IPAddressIterator struct {
Start net.IP
End net.IP
value net.IP
}
// Returns true if the iterator is not over, and shifts to the next value
func (ipr *IPAddressIterator) Next() bool {
if ipr.value == nil {
ipr.value = ipr.Start
} else {
inc(ipr.value)
}
return bytes.Compare(ipr.value, ipr.End) <= 0
}
// Returns the current value of the iterator.
func (ipr *IPAddressIterator) Value() net.IP {
if ipr.value == nil {
panic("Value not initialized, call IPRangeIterator.Next() first")
}
return ipr.value
}
// Increments byte array from right to left
func inc(addr []byte) {
for i := len(addr) - 1; i >= 0; i-- {
addr[i] += 1
if addr[i] != 0 {
break
}
}
}
Тогда ваш код перебора адресов можно сильно упростить:
// Create input line scanner.
scanner := bufio.NewScanner(inputFile)
ipRanges := []IPAddressIterator{}
lineCount := 0
for scanner.Scan() {
lineCount++
line := strings.TrimRight(scanner.Text(), "\n")
partsIP := strings.Split(line, "-")
firstIP := net.ParseIP(partsIP[0])
secondIP := net.ParseIP(partsIP[1])
ipRange := IPAddressIterator{
Start: firstIP,
End: secondIP,
}
ipRanges = append(ipRanges, ipRange)
}
for _, iter := range ipRanges {
for iter.Next() {
fmt.Fprintln(outputFile, iter.Value())
}
}
На примере 31.22.48.0-31.22.50.15 этот код отрабатывает за 40 миллисекунд, генерирует 528 адресов (256+256+16)