Skip to content

Instantly share code, notes, and snippets.

@Samu31Nd
Created January 6, 2025 05:24
Show Gist options
  • Select an option

  • Save Samu31Nd/fc8492ce67c009ec10956265794c08ce to your computer and use it in GitHub Desktop.

Select an option

Save Samu31Nd/fc8492ce67c009ec10956265794c08ce to your computer and use it in GitHub Desktop.
GBN with Files
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"`
}
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.
}
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
}
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