Created
January 6, 2025 05:24
-
-
Save Samu31Nd/fc8492ce67c009ec10956265794c08ce to your computer and use it in GitHub Desktop.
GBN with Files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| const ( | |
| ErrorCommunication int = iota - 1 | |
| StartCommunication | |
| ContinueCommunication | |
| EndCommunication | |
| SizeOfParts = 900 //since the header adds some space, we reduce the size of the file content | |
| ) | |
| type PackageModel struct { | |
| IDPackage int `json:"id-package"` | |
| PackageType int `json:"type"` | |
| Message string `json:"content"` | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| func enqueue(queue []int, element int) []int { | |
| queue = append(queue, element) // Simply append to enqueue. | |
| return queue | |
| } | |
| func dequeue(queue []int) (int, []int) { | |
| element := queue[0] // The first element is the one to be dequeued. | |
| if len(queue) <= 1 { | |
| var tmp []int | |
| return element, tmp | |
| } | |
| return element, queue[1:] // Slice off the element once it is dequeued. | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "encoding/json" | |
| "fmt" | |
| "log" | |
| "net" | |
| "os" | |
| "strings" | |
| "time" | |
| ) | |
| const ( | |
| WsR = 4 | |
| TimeoutReceiver = 3 * time.Second | |
| ) | |
| func main() { | |
| addr := net.UDPAddr{ | |
| IP: net.IPv4(127, 0, 0, 1), | |
| Port: 8080, | |
| } | |
| conn, connectionErr := net.ListenUDP("udp", &addr) | |
| if connectionErr != nil { | |
| log.Fatal(connectionErr) | |
| return | |
| } | |
| defer func(conn *net.UDPConn) { | |
| err := conn.Close() | |
| if err != nil { | |
| log.Fatal(err) | |
| return | |
| } | |
| }(conn) | |
| fmt.Printf("Server UDP listening in: [%s]\n", addr.String()) | |
| buffer := make([]byte, 1024) | |
| for { | |
| deadlineErr := conn.SetReadDeadline(time.Time{}) | |
| if deadlineErr != nil { | |
| log.Fatal("SetReadDeadline error:", deadlineErr) | |
| return | |
| } | |
| n, clientAddr, readErr := conn.ReadFromUDP(buffer) | |
| if readErr != nil { | |
| log.Fatal("Error trying to connect: " + readErr.Error()) | |
| return | |
| } | |
| var handshakePackage PackageModel | |
| unmarshallErr := json.Unmarshal(buffer[:n], &handshakePackage) | |
| if unmarshallErr != nil { | |
| log.Fatal(unmarshallErr) | |
| return | |
| } | |
| if handshakePackage.IDPackage != 0 { | |
| fmt.Println("Not a handshake...") | |
| continue | |
| } | |
| fmt.Println("Handshake received from", clientAddr, "! Starting communication...") | |
| constraints := strings.Split(string(handshakePackage.Message), ",") | |
| nameFile, totalSizeFile, totalParts := constraints[0], constraints[1], constraints[2] | |
| fmt.Println("Name:", nameFile, "\nParts:", totalParts, "\nSize:", totalSizeFile) | |
| data, _ := json.Marshal(handshakePackage) | |
| _, writeErr := conn.WriteToUDP(data, clientAddr) | |
| if writeErr != nil { | |
| log.Fatal(writeErr) | |
| return | |
| } | |
| //Receive | |
| packages, err := receivePackagesGBN(conn, clientAddr) | |
| if err != nil { | |
| return | |
| } | |
| savingErr := saveFile(nameFile, packages) | |
| if savingErr != nil { | |
| log.Fatal("Error al guardar el archivo") | |
| return | |
| } | |
| fmt.Println("Archivo descargado correctamente!") | |
| //printPackageReceived(packages) | |
| } | |
| } | |
| func printPackageReceived(packages []byte) { | |
| fmt.Println(string(packages)) | |
| } | |
| func receivePackagesGBN(conn *net.UDPConn, clientAddr *net.UDPAddr) ([]byte, error) { | |
| var packages []PackageModel | |
| var contentFile []byte | |
| var idsAck []int | |
| buffer := make([]byte, 1024) | |
| var packageReceived PackageModel | |
| expectedPackage := 1 | |
| deadlineErr := conn.SetReadDeadline(time.Now().Add(TimeoutReceiver)) | |
| if deadlineErr != nil { | |
| log.Fatal("SetReadDeadline error:", deadlineErr) | |
| return nil, deadlineErr | |
| } | |
| i := 0 | |
| for { | |
| //RECEIVE | |
| for i = 0; i < WsR; i++ { | |
| n, _, readErr := conn.ReadFromUDP(buffer) | |
| if readErr != nil { | |
| fmt.Println("Reading error:", readErr) | |
| return nil, readErr | |
| } | |
| parts := strings.SplitN(string(buffer[:n]), "\n", 2) | |
| jsonPart := parts[0] | |
| contentPart := []byte(parts[1]) | |
| unmarshalErr := json.Unmarshal([]byte(jsonPart), &packageReceived) | |
| if unmarshalErr != nil { | |
| log.Fatal("Unmarshal error:", unmarshalErr) | |
| return nil, unmarshalErr | |
| } | |
| fmt.Println("Received from sender:", packageReceived.IDPackage) | |
| if packageReceived.IDPackage == expectedPackage { | |
| packages = append(packages, packageReceived) | |
| contentFile = append(contentFile, contentPart...) | |
| expectedPackage++ | |
| } else { | |
| fmt.Printf("Not what we expected..., wanted %d and got %d\n", expectedPackage, packageReceived.IDPackage) | |
| } | |
| idsAck = enqueue(idsAck, expectedPackage-1) | |
| if packageReceived.PackageType == EndCommunication { | |
| break | |
| } | |
| } | |
| // CONFIRM | |
| var lastAck int | |
| for j := 0; j < i; j++ { | |
| if len(idsAck) == 0 { | |
| lastAck = expectedPackage | |
| } else { | |
| lastAck, idsAck = dequeue(idsAck) | |
| } | |
| messageToSend := PackageModel{ | |
| IDPackage: lastAck, | |
| PackageType: ContinueCommunication, | |
| Message: "ACK", | |
| } | |
| fmt.Println("Sending number:", lastAck) | |
| data, _ := json.Marshal(messageToSend) | |
| _, writeErr := conn.WriteToUDP(data, clientAddr) | |
| if writeErr != nil { | |
| log.Fatal("Cant write in UDP:", writeErr) | |
| return nil, writeErr | |
| } | |
| } | |
| if packageReceived.PackageType == EndCommunication { | |
| messageToSend := PackageModel{ | |
| IDPackage: expectedPackage - 1, | |
| PackageType: EndCommunication, | |
| Message: "ACK", | |
| } | |
| fmt.Println("Sending number:", expectedPackage-1) | |
| data, _ := json.Marshal(messageToSend) | |
| _, writeErr := conn.WriteToUDP(data, clientAddr) | |
| if writeErr != nil { | |
| log.Fatal("Cant write in UDP:", writeErr) | |
| return nil, writeErr | |
| } | |
| fmt.Println("End of communication") | |
| break | |
| } | |
| } | |
| return contentFile, nil | |
| } | |
| func saveFile(fileName string, data []byte) error { | |
| // Crear o truncar el archivo (modo escritura) | |
| file, err := os.Create("received/" + fileName) | |
| if err != nil { | |
| return err | |
| } | |
| defer file.Close() // Cerrar el archivo al finalizar | |
| // Escribir los datos en el archivo | |
| _, err = file.Write(data) | |
| return err | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "encoding/json" | |
| "fmt" | |
| "log" | |
| "net" | |
| "os" | |
| "time" | |
| ) | |
| var ( | |
| fileRoute = "toSend/ztm.png" | |
| ) | |
| const ( | |
| WsS = 4 | |
| TimeoutSender = 3 * time.Second | |
| ) | |
| func main() { | |
| //START OF THE COMMUNICATION | |
| conn, dialErr := net.Dial("udp", "127.0.0.1:8080") | |
| if dialErr != nil { | |
| log.Fatal("Dial error:", dialErr) | |
| return | |
| } | |
| //IN THE END OF THE EXECUTION, MUST CLOSE COMMUNICATION CHANNEL | |
| defer func(conn net.Conn) { | |
| err := conn.Close() | |
| if err != nil { | |
| log.Fatal(err) | |
| return | |
| } | |
| }(conn) | |
| //CREATE PACKAGES | |
| Packages, PackagesMarshalled, handshakePackage, packageCreationErr := CreatePackages() | |
| //_, PackagesMarshalled, _, packageCreationErr := CreatePackages() | |
| if packageCreationErr != nil { | |
| return | |
| } | |
| //printPackages(PackagesMarshalled) | |
| handshakeError := handshakeWithConn(conn, handshakePackage) | |
| if handshakeError != nil { | |
| return | |
| } | |
| gbnSender(conn, Packages, PackagesMarshalled) | |
| } | |
| func printPackages(packages [][]byte) { | |
| for i := 0; i < len(packages); i++ { | |
| fmt.Printf("%v\n\n", string(packages[i])) | |
| } | |
| } | |
| func CreatePackages() ([]PackageModel, [][]byte, []byte, error) { | |
| var packagesMarshalled [][]byte | |
| var packages []PackageModel | |
| file, fileOpenErr := os.Open(fileRoute) | |
| if fileOpenErr != nil { | |
| log.Fatal(fileOpenErr) | |
| return nil, nil, nil, fileOpenErr | |
| } | |
| defer func(file *os.File) { | |
| fileCloseErr := file.Close() | |
| if fileCloseErr != nil { | |
| log.Fatal("Error closing file:", fileCloseErr) | |
| } | |
| }(file) | |
| stats, _ := file.Stat() | |
| numberOfParts := int(stats.Size()) / SizeOfParts | |
| lastPartSize := int(stats.Size()) % SizeOfParts | |
| handshake := PackageModel{ | |
| IDPackage: 0, | |
| PackageType: StartCommunication, | |
| Message: fmt.Sprintf("%s,%d,%d", stats.Name(), stats.Size(), numberOfParts+1), | |
| } | |
| handshakeMarshalled, _ := json.Marshal(handshake) | |
| content := make([]byte, SizeOfParts) | |
| for i := 0; i < numberOfParts; i++ { | |
| _, fileReadErr := file.Read(content) | |
| if fileReadErr != nil { | |
| log.Fatal("File Read Error:", fileReadErr) | |
| return nil, nil, nil, fileReadErr | |
| } | |
| miniPackage := PackageModel{ | |
| IDPackage: i + 1, | |
| PackageType: ContinueCommunication, | |
| } | |
| miniPackageMarshalled, _ := json.Marshal(miniPackage) | |
| miniPackageMarshalled = append(miniPackageMarshalled, []byte("\n")...) | |
| miniPackageMarshalled = append(miniPackageMarshalled, content...) | |
| packagesMarshalled = append(packagesMarshalled, miniPackageMarshalled) | |
| packages = append(packages, miniPackage) | |
| } | |
| if lastPartSize > 0 { | |
| lastPart := make([]byte, lastPartSize) | |
| _, fileReadErr := file.Read(lastPart) | |
| if fileReadErr != nil { | |
| log.Fatal("File Read Error:", fileReadErr) | |
| return nil, nil, nil, fileOpenErr | |
| } | |
| miniPackage := PackageModel{ | |
| IDPackage: numberOfParts + 1, | |
| PackageType: EndCommunication, | |
| } | |
| miniPackageMarshalled, _ := json.Marshal(miniPackage) | |
| miniPackageMarshalled = append(miniPackageMarshalled, []byte("\n")...) | |
| miniPackageMarshalled = append(miniPackageMarshalled, lastPart...) | |
| packagesMarshalled = append(packagesMarshalled, miniPackageMarshalled) | |
| packages = append(packages, miniPackage) | |
| } | |
| return packages, packagesMarshalled, handshakeMarshalled, nil | |
| } | |
| func handshakeWithConn(conn net.Conn, handshakePackage []byte) error { | |
| errTimer := conn.SetReadDeadline(time.Now().Add(TimeoutSender)) | |
| if errTimer != nil { | |
| log.Fatal(errTimer) | |
| return errTimer | |
| } | |
| for { | |
| // HANDSHAKE SEND PHASE | |
| _, writeErr := conn.Write(handshakePackage) | |
| if writeErr != nil { | |
| log.Fatal("Handshake error:", writeErr) | |
| return writeErr | |
| } | |
| //ACK PHASE | |
| var responsePackage PackageModel | |
| buffer := make([]byte, 1024) | |
| n, readErr := conn.Read(buffer) | |
| if readErr != nil { | |
| log.Fatal("Read error in handshake:", readErr) | |
| return readErr | |
| } | |
| unmarshalErr := json.Unmarshal(buffer[:n], &responsePackage) | |
| if unmarshalErr != nil { | |
| log.Fatal("Unmarshal error:", unmarshalErr) | |
| return unmarshalErr | |
| } | |
| if responsePackage.IDPackage == 0 && | |
| responsePackage.PackageType != ErrorCommunication { | |
| fmt.Println("Handshake completed, starting sending!") | |
| return nil | |
| } | |
| } | |
| } | |
| func gbnSender(conn net.Conn, packages []PackageModel, packagesMarshalled [][]byte) { | |
| var window [WsS][]byte | |
| buffer := make([]byte, 1024) | |
| base := 0 | |
| var i int | |
| lastPackageConfirmed := 1 | |
| for { | |
| // SENDING PHASE | |
| for i = 0; i < 4; i++ { | |
| window[i] = packagesMarshalled[(base*4)+i] | |
| _, writeErr := conn.Write(window[i]) | |
| if writeErr != nil { | |
| log.Fatal("Error sending!:", writeErr) | |
| return | |
| } | |
| fmt.Println("Package sent:", (base*4)+i) | |
| if packages[(base*4)+i].PackageType == EndCommunication { | |
| i++ | |
| break | |
| } | |
| } | |
| // ACK BUCLE | |
| for j := 0; j < i; j++ { | |
| n, readErr := conn.Read(buffer) | |
| if readErr != nil { | |
| fmt.Println("Error reading in the ack bucle:", readErr) | |
| return | |
| } | |
| var ackReceived PackageModel | |
| unmarshalErr := json.Unmarshal(buffer[:n], &ackReceived) | |
| if unmarshalErr != nil { | |
| log.Fatal("Unmarshal error:", unmarshalErr) | |
| return | |
| } | |
| if ackReceived.IDPackage != lastPackageConfirmed { | |
| fmt.Println("Not the package we expected...") | |
| fmt.Printf("Expected [%v], got [%v]\n", lastPackageConfirmed, ackReceived.IDPackage) | |
| continue | |
| } | |
| fmt.Println("Package received:", lastPackageConfirmed) | |
| lastPackageConfirmed++ | |
| if ackReceived.PackageType == EndCommunication { | |
| return | |
| } | |
| if (lastPackageConfirmed)%4 == 0 { | |
| base++ | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment