Skip to content

Commit 4306254

Browse files
committed
✨ setup tcp and upd sample
0 parents  commit 4306254

File tree

15 files changed

+768
-0
lines changed

15 files changed

+768
-0
lines changed

.github/workflows/go.yml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Go
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
branches:
9+
- master
10+
jobs:
11+
build_and_test:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Setup go-task
15+
uses: pnorton5432/setup-task@v1
16+
with:
17+
task-version: 3.29.1
18+
- name: Checkout
19+
uses: actions/checkout@v4
20+
- name: Setup Go
21+
uses: actions/setup-go@v5
22+
with:
23+
go-version: 'stable'
24+
check-latest: true
25+
- name: Task Build for mage
26+
run: task build-gg
27+
- name: Test with gg
28+
run: ./gg test

.gitignore

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# If you prefer the allow list template instead of the deny list, see community template:
2+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3+
#
4+
# Binaries for programs and plugins
5+
*.exe
6+
*.exe~
7+
*.dll
8+
*.so
9+
*.dylib
10+
11+
# Test binary, built with `go test -c`
12+
*.test
13+
14+
# Output of the go coverage tool, specifically when used with LiteIDE
15+
*.out
16+
17+
# Dependency directories (remove the comment below to include it)
18+
# vendor/
19+
20+
# Go workspace file
21+
go.work
22+
go.work.sum
23+
24+
# env file
25+
.env
26+
gg
27+
mage
28+
bin

README.md

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# golang-sample-with-tcp-udp-socket
2+
3+
This repository is demo how to use tcp and udp socket in golang
4+
5+
## tcp logic
6+
7+
```golang
8+
func main() {
9+
// setup logger
10+
ctx := context.Background()
11+
ulog := logger.FromContext(ctx)
12+
// create tcp socket
13+
listener, err := net.Listen("tcp", config.AppConfig.ServerURI)
14+
if err != nil {
15+
ulog.ErrorContext(ctx, "failed to listen", slog.Any("addr", listener.Addr().String()))
16+
os.Exit(1)
17+
}
18+
defer listener.Close()
19+
20+
for {
21+
// Accept an incoming connection
22+
conn, err := listener.Accept()
23+
if err != nil {
24+
ulog.ErrorContext(ctx, "failed to accept request", slog.Any("err", err))
25+
}
26+
27+
// Handle the connection
28+
go handleConnectionNonBlocking(ctx, conn)
29+
}
30+
}
31+
32+
// handleConnectionNonBlocking - nonblock reading with setup conn read/write timeout
33+
func handleConnectionNonBlocking(ctx context.Context, conn net.Conn) {
34+
hlog := logger.FromContext(ctx)
35+
defer conn.Close()
36+
for {
37+
// Set a deadline for reading data
38+
conn.SetReadDeadline(time.Now().Add(time.Second))
39+
// Read from client
40+
buf := make([]byte, 1024)
41+
// block util read timeout
42+
n, err := conn.Read(buf)
43+
if err != nil {
44+
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
45+
// The read operation timeout, continue waiting for next read
46+
continue
47+
} else if !errors.Is(err, io.EOF) {
48+
// Other errors (client disconnected, etc)
49+
hlog.ErrorContext(ctx, "Connection closed", slog.Any("err", err))
50+
break
51+
}
52+
}
53+
if n > 0 {
54+
msg := string(buf[:n])
55+
hlog.InfoContext(ctx, "Received", slog.String("message", msg))
56+
57+
// Set a deadline for writing data
58+
conn.SetWriteDeadline(time.Now().Add(time.Second))
59+
// Send a response to the client
60+
_, err = fmt.Fprintf(conn, "Echo - %s", msg)
61+
if err != nil {
62+
hlog.ErrorContext(ctx, "error writing to client", slog.Any("err", err))
63+
break
64+
}
65+
}
66+
}
67+
}
68+
```
69+
## udp logic
70+
```golang
71+
func main() {
72+
// setup logger
73+
ctx := context.Background()
74+
ulog := logger.FromContext(ctx)
75+
// setup connection socket with udp
76+
addr, err := net.ResolveUDPAddr("udp", config.AppConfig.ServerURI)
77+
if err != nil {
78+
ulog.InfoContext(ctx, "failed to resolve addr", slog.Any("err", err))
79+
os.Exit(1)
80+
}
81+
conn, err := net.ListenUDP("udp", addr)
82+
if err != nil {
83+
ulog.ErrorContext(ctx, "failed to listen udp", slog.Any("err", err))
84+
os.Exit(2)
85+
}
86+
defer conn.Close()
87+
88+
for {
89+
// Read a message from the client
90+
buf := make([]byte, 1024)
91+
n, clientAddr, err := conn.ReadFromUDP(buf)
92+
if err != nil {
93+
ulog.ErrorContext(ctx, "Error reading", slog.Any("err", err))
94+
continue
95+
}
96+
97+
if n > 0 {
98+
msg := string(buf[:n])
99+
// Print received message
100+
ulog.InfoContext(ctx, "Received message", slog.Any("clientAddr", clientAddr), slog.String("message", msg))
101+
// Send response to the client
102+
_, err = conn.WriteToUDP([]byte("Hey client!"), clientAddr)
103+
if err != nil {
104+
ulog.ErrorContext(ctx, "error writing", slog.Any("err", err))
105+
}
106+
}
107+
}
108+
}
109+
```

Taskfile.yml

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
version: '3'
2+
3+
dotenv: ['.env']
4+
5+
tasks:
6+
default:
7+
cmds:
8+
- echo "SERVER_URI=$SERVER_URI"
9+
silent: true
10+
11+
# build:
12+
# cmds:
13+
# - CGO_ENABLED=0 GOOS=linux go build -o bin/main cmd/main.go
14+
# silent: true
15+
# run:
16+
# cmds:
17+
# - ./bin/main
18+
# deps:
19+
# - build
20+
# silent: true
21+
22+
build-mage:
23+
cmds:
24+
- CGO_ENABLED=0 GOOS=linux go build -o ./mage mage-tools/mage.go
25+
silent: true
26+
27+
build-gg:
28+
cmds:
29+
- ./mage -d mage-tools -compile ../gg
30+
deps:
31+
- build-mage
32+
silent: true
33+
34+
coverage:
35+
cmds:
36+
- go test -v -cover ./...
37+
silent: true
38+
test:
39+
cmds:
40+
- go test -v ./...
41+
silent: true
42+

cmd/tcp-client/main.go

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log/slog"
7+
"net"
8+
"os"
9+
10+
"github.com/leetcode-golang-classroom/golang-sample-with-tcp-udp-socket/internal/config"
11+
"github.com/leetcode-golang-classroom/golang-sample-with-tcp-udp-socket/internal/logger"
12+
)
13+
14+
func main() {
15+
// setup logger
16+
ctx := context.Background()
17+
ulog := logger.FromContext(ctx)
18+
// Create a TCP socket
19+
conn, err := net.Dial("tcp", config.AppConfig.ServerURI)
20+
if err != nil {
21+
ulog.ErrorContext(ctx, "failed to connect tcp", slog.Any("err", err))
22+
os.Exit(1)
23+
}
24+
25+
// Send a message
26+
fmt.Fprint(conn, "Hello!")
27+
28+
// Read a response
29+
buf := make([]byte, 1024)
30+
n, err := conn.Read(buf)
31+
if err != nil {
32+
ulog.ErrorContext(ctx, "failed to read", slog.Any("err", err))
33+
}
34+
msg := string(buf[:n])
35+
ulog.InfoContext(ctx, "server reply", slog.String("message", msg))
36+
conn.Close()
37+
}

cmd/tcp-server/main.go

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"io"
8+
"log/slog"
9+
"net"
10+
"os"
11+
"time"
12+
13+
"github.com/leetcode-golang-classroom/golang-sample-with-tcp-udp-socket/internal/config"
14+
"github.com/leetcode-golang-classroom/golang-sample-with-tcp-udp-socket/internal/logger"
15+
)
16+
17+
func main() {
18+
// setup logger
19+
ctx := context.Background()
20+
ulog := logger.FromContext(ctx)
21+
// create tcp socket
22+
listener, err := net.Listen("tcp", config.AppConfig.ServerURI)
23+
if err != nil {
24+
ulog.ErrorContext(ctx, "failed to listen", slog.Any("addr", listener.Addr().String()))
25+
os.Exit(1)
26+
}
27+
defer listener.Close()
28+
29+
for {
30+
// Accept an incoming connection
31+
conn, err := listener.Accept()
32+
if err != nil {
33+
ulog.ErrorContext(ctx, "failed to accept request", slog.Any("err", err))
34+
}
35+
36+
// Handle the connection
37+
go handleConnectionNonBlocking(ctx, conn)
38+
}
39+
}
40+
41+
// handleConnectionNonBlocking - nonblock reading with setup conn read/write timeout
42+
func handleConnectionNonBlocking(ctx context.Context, conn net.Conn) {
43+
hlog := logger.FromContext(ctx)
44+
defer conn.Close()
45+
for {
46+
// Set a deadline for reading data
47+
conn.SetReadDeadline(time.Now().Add(time.Second))
48+
// Read from client
49+
buf := make([]byte, 1024)
50+
// block util read timeout
51+
n, err := conn.Read(buf)
52+
if err != nil {
53+
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
54+
// The read operation timeout, continue waiting for next read
55+
continue
56+
} else if !errors.Is(err, io.EOF) {
57+
// Other errors (client disconnected, etc)
58+
hlog.ErrorContext(ctx, "Connection closed", slog.Any("err", err))
59+
break
60+
}
61+
}
62+
if n > 0 {
63+
msg := string(buf[:n])
64+
hlog.InfoContext(ctx, "Received", slog.String("message", msg))
65+
66+
// Set a deadline for writing data
67+
conn.SetWriteDeadline(time.Now().Add(time.Second))
68+
// Send a response to the client
69+
_, err = fmt.Fprintf(conn, "Echo - %s", msg)
70+
if err != nil {
71+
hlog.ErrorContext(ctx, "error writing to client", slog.Any("err", err))
72+
break
73+
}
74+
}
75+
}
76+
}

cmd/udp-client/main.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"log/slog"
6+
"net"
7+
"os"
8+
"time"
9+
10+
"github.com/leetcode-golang-classroom/golang-sample-with-tcp-udp-socket/internal/config"
11+
"github.com/leetcode-golang-classroom/golang-sample-with-tcp-udp-socket/internal/logger"
12+
)
13+
14+
func main() {
15+
// setup logger
16+
ctx := context.Background()
17+
ulog := logger.FromContext(ctx)
18+
// Create UDP connection
19+
conn, err := net.Dial("udp", config.AppConfig.ServerURI)
20+
if err != nil {
21+
ulog.ErrorContext(ctx, "failed to dial", slog.Any("err", err))
22+
os.Exit(1)
23+
}
24+
defer conn.Close()
25+
26+
// Send message to the server
27+
message := "Hello UDP Server"
28+
_, err = conn.Write([]byte(message))
29+
if err != nil {
30+
ulog.ErrorContext(ctx, "failed to sending message", slog.Any("err", err))
31+
return
32+
}
33+
ulog.InfoContext(ctx, "Sent:", slog.String("message", message))
34+
// Set read deadline to avoid blocking indefinitely
35+
conn.SetReadDeadline(time.Now().Add(5 * time.Second))
36+
37+
// Receive response from server
38+
buf := make([]byte, 1024)
39+
n, err := conn.Read(buf)
40+
if err != nil {
41+
ulog.InfoContext(ctx, "errror reading from server", slog.Any("err", err))
42+
return
43+
}
44+
if n > 0 {
45+
receivedMsg := string(buf[:n])
46+
ulog.InfoContext(ctx, "Received:", slog.String("receivedMsg", receivedMsg))
47+
}
48+
}

0 commit comments

Comments
 (0)