Go 언어로 구현하는 네트워크 프로토콜 🚀
안녕하세요, 여러분! 오늘은 정말 흥미진진한 주제로 여러분과 함께 시간을 보내려고 해요. 바로 Go 언어를 사용해 네트워크 프로토콜을 구현하는 방법에 대해 알아볼 거예요. 🎉
네트워크 프로토콜이라고 하면 뭔가 어렵고 복잡할 것 같죠? 하지만 걱정 마세요! 우리는 마치 레고 블록을 조립하듯이, 차근차근 재미있게 배워나갈 거예요. 😊
Go 언어는 구글에서 개발한 프로그래밍 언어로, 특히 네트워크 프로그래밍에 강점을 가지고 있어요. 마치 슈퍼히어로가 특별한 능력을 가진 것처럼, Go는 네트워크 관련 작업을 수행하는 데 탁월한 능력을 가지고 있답니다! 🦸♂️
이 글을 통해 여러분은 Go 언어의 기본부터 시작해서, 실제로 동작하는 네트워크 프로토콜을 구현하는 방법까지 배우게 될 거예요. 마치 요리 레시피를 따라 맛있는 요리를 만드는 것처럼, 우리도 함께 멋진 네트워크 프로그램을 만들어볼 거예요! 🍳
그리고 혹시 여러분 중에 이런 기술을 배우고 나서 "어떻게 활용할 수 있을까?" 고민하시는 분들이 계신다면, 재능넷(https://www.jaenung.net)이라는 플랫폼을 소개해드리고 싶어요. 여기서 여러분의 새로운 기술을 다른 사람들과 공유하고, 또 다른 재능을 배울 수 있답니다! 🌟
자, 그럼 이제 본격적으로 Go 언어의 세계로 들어가볼까요? 안전벨트 꽉 매세요, 신나는 여행이 시작됩니다! 🚗💨
1. Go 언어 소개: 네트워크 프로그래밍의 슈퍼히어로 🦸♂️
여러분, Go 언어에 대해 들어보신 적 있나요? 아직 모르신다고요? 걱정 마세요! 지금부터 Go 언어가 얼마나 멋진 녀석인지 소개해드릴게요. 😎
Go 언어의 특징:
- 간결하고 읽기 쉬운 문법 📚
- 빠른 컴파일 속도 ⚡
- 강력한 동시성 지원 🔄
- 효율적인 가비지 컬렉션 🗑️
- 풍부한 표준 라이브러리 📦
Go 언어는 2009년에 구글의 천재 프로그래머들이 만든 언어예요. 그들은 "왜 프로그래밍이 이렇게 복잡해야 하지?"라고 생각했죠. 그래서 탄생한 것이 바로 Go 언어랍니다!
Go는 마치 슈퍼히어로처럼 여러 가지 특별한 능력을 가지고 있어요:
- 초스피드 컴파일: Go는 번개처럼 빠르게 컴파일돼요. C++이나 Java가 커피 한 잔 마실 동안 컴파일되는 동안, Go는 이미 실행을 마치고 "다 했어요!"라고 말할 거예요. ☕➡️🚀
- 동시성의 마법사: Go의 고루틴(goroutine)과 채널(channel)을 사용하면, 복잡한 동시성 프로그래밍도 마법처럼 쉬워져요. 마치 여러 분신을 만들어 동시에 여러 일을 처리하는 것과 같죠! 🧙♂️✨
- 가비지 컬렉션의 청소부: 메모리 관리? 걱정 마세요! Go의 가비지 컬렉터가 알아서 깔끔하게 처리해줘요. 여러분은 그저 코딩에만 집중하세요. 🧹✨
- 표준 라이브러리의 보물창고: Go의 표준 라이브러리는 마치 도라에몽의 4차원 주머니 같아요. 필요한 도구가 거의 다 들어있죠! 특히 네트워크 프로그래밍에 필요한 도구들이 풍성하답니다. 🎒💎
이런 특징들 때문에 Go는 특히 네트워크 프로그래밍에 아주 적합해요. 복잡한 네트워크 통신도 Go를 사용하면 마치 레고 블록을 조립하듯 쉽고 재미있게 만들 수 있답니다! 🧱🔧
그럼 이제 Go 언어의 기본 문법을 살펴볼까요? Go 언어의 "Hello, World!"를 만나볼 시간이에요!
package main
import "fmt"
func main() {
fmt.Println("Hello, 네트워크 세상!")
}
와! 정말 간단하죠? 이 코드를 실행하면 콘솔에 "Hello, 네트워크 세상!"이라고 출력될 거예요. 🌍
이제 여러분은 Go 언어의 매력에 푹 빠지셨나요? 😍 Go 언어는 정말 재미있고 강력한 도구예요. 특히 네트워크 프로그래밍을 할 때 그 진가를 발휘한답니다.
다음 섹션에서는 Go 언어를 사용해 실제로 네트워크 프로그래밍을 어떻게 하는지 알아볼 거예요. 준비되셨나요? 우리의 네트워크 모험이 이제 막 시작됐어요! 🚀
🌟 재능넷 Tip: Go 언어를 배우고 나면, 여러분의 새로운 기술을 재능넷에서 공유해보는 건 어떨까요? 다른 사람들에게 Go 언어의 매력을 전파하고, 동시에 여러분의 지식을 나누는 멋진 경험이 될 거예요!
2. Go로 시작하는 네트워크 프로그래밍: 첫 걸음 👣
자, 이제 본격적으로 Go를 사용해 네트워크 프로그래밍을 시작해볼까요? 😃 네트워크 프로그래밍이라고 하면 뭔가 어렵고 복잡할 것 같지만, Go와 함께라면 그리 어렵지 않아요!
우리의 첫 번째 미션은 간단한 TCP 서버와 클라이언트를 만드는 것이에요. 마치 전화기의 송수신기를 만드는 것과 비슷하답니다. 🎧📞
2.1 TCP 서버 만들기
먼저 TCP 서버를 만들어볼게요. 이 서버는 클라이언트의 연결을 기다리고, 연결이 되면 "안녕하세요!"라는 메시지를 보내줄 거예요.
package main
import (
"fmt"
"net"
)
func main() {
// 8080 포트에서 TCP 연결을 수신합니다.
listener, err := net.Listen("tcp", ":8080")
if err != nil {
fmt.Println("서버를 시작하는 데 문제가 발생했어요:", err)
return
}
defer listener.Close()
fmt.Println("서버가 8080 포트에서 실행 중입니다...")
for {
// 클라이언트의 연결을 기다립니다.
conn, err := listener.Accept()
if err != nil {
fmt.Println("클라이언트 연결에 문제가 발생했어요:", err)
continue
}
// 고루틴을 사용해 클라이언트를 처리합니다.
go handleClient(conn)
}
}
func handleClient(conn net.Conn) {
defer conn.Close()
// 클라이언트에게 메시지를 보냅니다.
conn.Write([]byte("안녕하세요! Go 네트워크 서버입니다!\n"))
}
와! 우리의 첫 번째 TCP 서버가 완성됐어요. 🎉 이 서버는 다음과 같이 동작해요:
- 8080 포트에서 TCP 연결을 기다립니다.
- 클라이언트가 연결하면, 새로운 고루틴을 만들어 클라이언트를 처리합니다.
- 클라이언트에게 "안녕하세요! Go 네트워크 서버입니다!" 메시지를 보냅니다.
- 연결을 닫고 다음 클라이언트를 기다립니다.
고루틴(goroutine)을 사용해 각 클라이언트를 처리하는 것에 주목해주세요. 이렇게 하면 여러 클라이언트를 동시에 처리할 수 있어요. 마치 레스토랑에서 여러 웨이터가 동시에 여러 테이블을 서빙하는 것과 같죠! 🍽️👨🍳👩🍳
2.2 TCP 클라이언트 만들기
이제 서버에 연결할 클라이언트를 만들어볼까요?
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
// 서버에 연결합니다.
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
fmt.Println("서버에 연결하는 데 문제가 발생했어요:", err)
return
}
defer conn.Close()
// 서버로부터 메시지를 읽습니다.
message, _ := bufio.NewReader(conn).ReadString('\n')
fmt.Print("서버로부터 받은 메시지: ", message)
// 사용자 입력을 받아 서버로 보냅니다.
for {
reader := bufio.NewReader(os.Stdin)
fmt.Print("서버에 보낼 메시지를 입력하세요: ")
text, _ := reader.ReadString('\n')
fmt.Fprintf(conn, text + "\n")
}
}
짜잔! 🎭 우리의 TCP 클라이언트도 완성됐어요. 이 클라이언트는:
- localhost의 8080 포트로 연결을 시도합니다.
- 서버로부터 받은 환영 메시지를 출력합니다.
- 사용자로부터 입력을 받아 서버로 전송합니다.
이제 우리는 완전한 TCP 통신 시스템을 만들었어요! 서버와 클라이언트가 서로 대화를 나눌 수 있게 된 거죠. 마치 두 사람이 전화로 이야기를 나누는 것과 같아요. 📞👥
🌟 실습 팁: 이 코드들을 직접 실행해보세요! 두 개의 터미널 창을 열어 하나는 서버를, 다른 하나는 클라이언트를 실행해보세요. 그리고 클라이언트에서 메시지를 입력해보세요. 어떤 일이 일어나나요?
우와, 정말 신기하지 않나요? 우리가 방금 만든 이 간단한 프로그램들이 실제로 인터넷의 기본 원리와 똑같이 동작한다는 사실! 🌐
이제 여러분은 Go를 사용해 기본적인 네트워크 프로그램을 만들 수 있게 됐어요. 이것이 바로 모든 복잡한 네트워크 애플리케이션의 기초랍니다. 페이스북, 트위터, 심지어 재능넷같은 플랫폼도 이런 기본 원리를 확장해서 만들어진 거예요!
다음 섹션에서는 좀 더 복잡한 네트워크 프로토콜을 구현해볼 거예요. HTTP 서버를 만들어볼 준비가 되셨나요? 우리의 네트워크 여행은 계속됩니다! 🚀
3. Go로 HTTP 서버 만들기: 웹의 세계로! 🌐
자, 이제 우리는 한 단계 더 나아가 볼 거예요. TCP 통신을 넘어서 실제 웹 서버를 만들어볼 시간이에요! 😃 HTTP(HyperText Transfer Protocol)는 웹의 기본이 되는 프로토콜이에요. 우리가 매일 사용하는 웹사이트들은 모두 이 프로토콜을 기반으로 동작하죠.
Go 언어는 강력한 표준 라이브러리를 제공하는데, 그 중에서도 net/http
패키지는 HTTP 클라이언트와 서버를 쉽게 구현할 수 있게 해줘요. 마치 레고 블록으로 집을 짓는 것처럼 간단하답니다! 🏠
3.1 간단한 HTTP 서버 만들기
먼저, 가장 기본적인 HTTP 서버를 만들어볼게요. 이 서버는 모든 요청에 대해 "안녕하세요, Go 웹 서버예요!"라고 응답할 거예요.
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "안녕하세요, Go 웹 서버예요!")
}
func main() {
http.HandleFunc("/", handler)
fmt.Println("서버가 8080 포트에서 실행 중입니다...")
http.ListenAndServe(":8080", nil)
}
와! 정말 간단하죠? 😲 이 코드는 다음과 같이 동작해요:
handler
함수는 모든 HTTP 요청을 처리합니다.http.HandleFunc("/")
는 루트 경로("/")로 오는 모든 요청을handler
함수로 보냅니다.http.ListenAndServe(":8080", nil)
는 8080 포트에서 HTTP 서버를 시작합니다.
이 서버를 실행하고 브라우저에서 http://localhost:8080
에 접속하면, "안녕하세요, Go 웹 서버예요!"라는 메시지를 볼 수 있어요. 축하합니다! 여러분의 첫 웹 서버가 탄생한 거예요! 🎉
3.2 동적 컨텐츠를 제공하는 HTTP 서버
이제 조금 더 재미있는 걸 해볼까요? 이번에는 방문자의 이름을 받아서 개인화된 인사말을 보내는 서버를 만들어볼게요.
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
if name == "" {
name = "익명의 방문자"
}
fmt.Fprintf(w, "안녕하세요, %s님! Go 웹 서버에 오신 것을 환영합니다!", name)
}
func main() {
http.HandleFunc("/", handler)
fmt.Println("서버가 8080 포트에서 실행 중입니다...")
http.ListenAndServe(":8080", nil)
}
이 서버는 URL 파라미터로 전달된 이름을 읽어서 개인화된 인사말을 보내줘요. 예를 들어, http://localhost:8080/?name=철수
로 접속하면 "안녕하세요, 철수님! Go 웹 서버에 오신 것을 환영합니다!"라고 응답할 거예요.
🚨 보안 주의: 실제 서비스에서는 사용자 입력을 그대로 출력하는 것은 위험할 수 있어요. XSS(Cross-Site Scripting) 공격의 위험이 있기 때문이죠. 항상 사용자 입력을 검증하고 이스케이프 처리를 해야 해요!
3.3 정적 파일 서빙하기
웹 서버의 중요한 기능 중 하나는 HTML, CSS, 자바스크립트, 이미지 등의 정적 파일을 제공하는 거예요. Go의 net/http
패키지는 이것도 아주 쉽게 할 수 있게 해줘요!
package main
import (
"fmt"
"net/http"
)
func main() {
// 정적 파일 서빙을 위한 핸들러 등록
fs := http.FileServer(http.Dir("static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
// 메인 페이지 핸들러
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "안녕하세요! 정적 파일은 /static/ 경로에서 확인하세요.")
})
fmt.Println("서버가 8080 포트에서 실행 중입니다...")
http.ListenAndServe(":8080", nil)
}
이 서버는 static
디렉토리에 있는 파일들을 /static/
경로로 서빙해요. 예를 들어, static/image.jpg
파일은 http://localhost:8080/static/image.jpg
로 접근할 수 있어요.
와! 우리가 만든 서버가 점점 더 멋져지고 있어요, 그렇죠? 🌟
3.4 RESTful API 구현하기
현대 웹 개발에서 RESTful API는 정말 중요한 개념이에요. Go를 사용하면 RESTful API도 쉽게 구현할 수 있어요. 간단한 TODO 리스트 API를 만들어볼까요?
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type Todo struct {
ID int `json:"id"`
Task string `json:"task"`
}
var todos []Todo
func main() {
todos = []Todo{
{ID: 1, Task: "Go 언어 배우기"},
{ID: 2, Task: "RESTful API 만들기"},
}
http.HandleFunc("/todos", handleTodos)
fmt.Println("서버가 8080 포트에서 실행 중입니다...")
http.ListenAndServe(":8080", nil)
}
func handleTodos(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
json.NewEncoder(w).Encode(todos)
case "POST":
var todo Todo
json.NewDecoder(r.Body).Decode(&todo)
todo.ID = len(todos) + 1
todos = append(todos, todo)
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(todo)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
이 API는 다음과 같은 기능을 제공해요:
- GET /todos: 모든 TODO 항목을 JSON 형식으로 반환
- POST /todos: 새로운 TODO 항목을 추가
이제 curl이나 Postman 같은 도구를 사용해 API를 테스트해볼 수 있어요!
💡 실습 아이디어: 이 TODO 리스트 API를 확장해보는 건 어떨까요? 항목 삭제(DELETE), 수정(PUT) 기능을 추가해보세요. 더 나아가 데이터를 파일이나 데이터베이스에 저장하는 기능을 구현해볼 수도 있어요!
여기까지 오신 여러분, 정말 대단해요! 👏 우리는 이제 Go를 사용해 기본적인 웹 서버부터 RESTful API까지 구현할 수 있게 됐어요. 이런 기술들은 재능넷과 같은 플랫폼을 만드는 데에도 사용될 수 있어요. 예를 들어, 재능 거래를 위한 API를 만들거나, 사용자 프로필을 관리하는 서비스를 구현하는 데 이런 기술들이 활용될 수 있죠.
다음 섹션에서는 더 복잡한 네트워크 프로토콜을 구현해볼 거예요. WebSocket을 사용한 실시간 통신에 대해 알아볼 준비가 되셨나요? 우리의 Go 네트워크 프로그래밍 여행은 계속됩니다! 🚀
4. WebSocket으로 실시간 통신 구현하기: 대화의 새로운 차원 🚀
여러분, 지금까지 정말 잘 따라오셨어요! 👏 이제 우리는 더 흥미진진한 영역으로 들어갈 거예요. 바로 WebSocket을 이용한 실시간 통신이에요. 이건 마치 텔레파시처럼 즉각적으로 메시지를 주고받을 수 있게 해주는 기술이에요! 😮
4.1 WebSocket이란?
WebSocket은 클라이언트와 서버 사이에 지속적인 양방향 연결을 제공하는 프로토콜이에요. 일반적인 HTTP 통신과는 달리, 한 번 연결이 established되면 양쪽에서 자유롭게 데이터를 주고받을 수 있어요. 이는 실시간 채팅, 실시간 게임, 실시간 주식 정보 등을 구현하는 데 아주 유용하답니다.
💡 WebSocket vs HTTP: HTTP는 클라이언트가 요청을 보내고 서버가 응답하는 방식이에요. 반면 WebSocket은 연결이 유지되는 동안 양쪽에서 언제든 메시지를 보낼 수 있어요. 마치 전화 통화처럼요! 📞
4.2 Go로 WebSocket 서버 만들기
Go로 WebSocket 서버를 만들기 위해 우리는 gorilla/websocket
패키지를 사용할 거예요. 이 패키지는 WebSocket 구현을 매우 쉽게 만들어줘요.
먼저, 다음 명령어로 패키지를 설치해주세요:
go get github.com/gorilla/websocket
이제 간단한 WebSocket 에코 서버를 만들어볼게요. 이 서버는 클라이언트로부터 메시지를 받으면 그대로 다시 보내줄 거예요.
package main
import (
"fmt"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func main() {
http.HandleFunc("/echo", handleWebSocket)
fmt.Println("서버가 8080 포트에서 실행 중입니다...")
http.ListenAndServe(":8080", nil)
}
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
for {
messageType, p, err := conn.ReadMessage()
if err != nil {
return
}
if err := conn.WriteMessage(messageType, p); err != nil {
return
}
}
}
이 코드는 다음과 같이 동작해요:
upgrader.Upgrade()
를 사용해 HTTP 연결을 WebSocket 연결로 업그레이드해요.- 무한 루프 안에서 메시지를 읽고(
conn.ReadMessage()
) 그대로 다시 보내요(conn.WriteMessage()
).
4.3 실시간 채팅 서버 구현하기
이제 우리의 지식을 활용해 간단한 실시간 채팅 서버를 만들어볼까요? 이 서버는 연결된 모든 클라이언트에게 메시지를 브로드캐스트할 거예요.
package main
import (
"fmt"
"net/http"
"sync"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
type Client struct {
conn *websocket.Conn
send chan []byte
}
type ChatRoom struct {
clients map[*Client]bool
broadcast chan []byte
register chan *Client
unregister chan *Client
}
func newChatRoom() *ChatRoom {
return &ChatRoom{
broadcast: make(chan []byte),
register: make(chan *Client),
unregister: make(chan *Client),
clients: make(map[*Client]bool),
}
}
func (cr *ChatRoom) run() {
for {
select {
case client := <-cr.register:
cr.clients[client] = true
case client := <-cr.unregister:
if _, ok := cr.clients[client]; ok {
delete(cr.clients, client)
close(client.send)
}
case message := <-cr.broadcast:
for client := range cr.clients {
select {
case client.send <- message:
default:
close(client.send)
delete(cr.clients, client)
}
}
}
}
}
func (cr *ChatRoom) handleWebSocket(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
fmt.Println(err)
return
}
client := &Client{conn: conn, send: make(chan []byte, 256)}
cr.register <- client
go client.writePump(cr)
go client.readPump(cr)
}
func (c *Client) readPump(cr *ChatRoom) {
defer func() {
cr.unregister <- c
c.conn.Close()
}()
for {
_, message, err := c.conn.ReadMessage()
if err != nil {
break
}
cr.broadcast <- message
}
}
func (c *Client) writePump(cr *ChatRoom) {
defer c.conn.Close()
for {
select {
case message, ok := <-c.send:
if !ok {
c.conn.WriteMessage(websocket.CloseMessage, []byte{})
return
}
w, err := c.conn.NextWriter(websocket.TextMessage)
if err != nil {
return
}
w.Write(message)
n := len(c.send)
for i := 0; i < n; i++ {
w.Write(<-c.send)
}
if err := w.Close(); err != nil {
return
}
}
}
}
func main() {
chatRoom := newChatRoom()
go chatRoom.run()
http.HandleFunc("/ws", chatRoom.handleWebSocket)
fmt.Println("채팅 서버가 8080 포트에서 실행 중입니다...")
http.ListenAndServe(":8080", nil)
}
와! 우리가 만든 채팅 서버를 보세요. 😍 이 서버는 다음과 같이 동작해요:
- 새로운 클라이언트가 연결되면
ChatRoom
에 등록돼요. - 클라이언트가 메시지를 보내면, 그 메시지는 모든 연결된 클라이언트에게 브로드캐스트돼요.
- 클라이언트가 연결을 끊으면
ChatRoom
에서 제거돼요.
🌟 실습 아이디어: 이 채팅 서버에 더 많은 기능을 추가해보는 건 어떨까요? 예를 들어, 사용자 이름을 추가하거나, 개인 메시지 기능을 구현하거나, 이모지 지원을 추가해볼 수 있어요!
이제 우리는 실시간으로 통신하는 강력한 채팅 서버를 가지게 됐어요. 이런 기술은 재능넷과 같은 플랫폼에서 실시간 메시징 시스템을 구현하는 데 사용될 수 있어요. 예를 들어, 재능 거래 중 실시간으로 판매자와 구매자가 대화를 나누는 기능을 만들 수 있죠.
WebSocket을 사용한 실시간 통신은 현대 웹 애플리케이션의 핵심 기술 중 하나예요. 여러분이 이 기술을 마스터하면, 훨씬 더 역동적이고 상호작용이 풍부한 웹 애플리케이션을 만들 수 있을 거예요!
다음 섹션에서는 우리가 배운 모든 것을 종합해서 더 복잡한 네트워크 애플리케이션을 만들어볼 거예요. 준비되셨나요? 우리의 Go 네트워크 프로그래밍 여행은 계속됩니다! 🚀
5. 종합 프로젝트: 미니 SNS 서비스 구현하기 🌟
축하합니다! 여러분은 이제 Go를 사용한 네트워크 프로그래밍의 기본을 모두 마스터했어요. 🎉 이제 우리의 지식을 총동원해서 미니 SNS 서비스를 만들어볼 거예요. 이 프로젝트는 HTTP 서버, RESTful API, WebSocket, 그리고 데이터베이스 연동까지 모든 것을 포함할 거예요!
5.1 프로젝트 구조
우리의 미니 SNS는 다음과 같은 기능을 가질 거예요:
- 사용자 등록 및 로그인 (RESTful API)
- 게시물 작성, 조회, 수정, 삭제 (RESTful API)
- 실시간 채팅 (WebSocket)
- 데이터베이스 연동 (PostgreSQL 사용)
5.2 데이터베이스 설정
먼저, PostgreSQL 데이터베이스를 설정하고 연결해볼게요. Go에서는 database/sql
패키지와 lib/pq
드라이버를 사용할 거예요.
go get github.com/lib/pq
데이터베이스 연결 코드:
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/lib/pq"
)
var db *sql.DB
func initDB() {
var err error
db, err = sql.Open("postgres", "user=username dbname=miniSNS sslmode=disable")
if err != nil {
log.Fatal(err)
}
if err = db.Ping(); err != nil {
log.Fatal(err)
}
fmt.Println("데이터베이스 연결 성공!")
}
5.3 사용자 관리 API
사용자 등록과 로그인을 위한 API를 만들어볼게요.
package main
import (
"encoding/json"
"net/http"
)
type User struct {
ID int `json:"id"`
Username string `json:"username"`
Password string `json:"password"`
}
func registerHandler(w http.ResponseWriter, r *http.Request) {
var user User
json.NewDecoder(r.Body).Decode(&user)
// 실제 구현에서는 비밀번호를 해시화해야 해요!
_, err := db.Exec("INSERT INTO users(username, password) VALUES($1, $2)", user.Username, user.Password)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(map[string]string{"message": "사용자 등록 성공"})
}
func loginHandler(w http.ResponseWriter, r *http.Request) {
var user User
json.NewDecoder(r.Body).Decode(&user)
var dbUser User
err := db.QueryRow("SELECT id, username, password FROM users WHERE username = $1", user.Username).Scan(&dbUser.ID, &dbUser.Username, &dbUser.Password)
if err != nil {
http.Error(w, "사용자를 찾을 수 없습니다", http.StatusUnauthorized)
return
}
if user.Password != dbUser.Password {
http.Error(w, "비밀번호가 일치하지 않습니다", http.StatusUnauthorized)
return
}
json.NewEncoder(w).Encode(map[string]string{"message": "로그인 성공"})
}
5.4 게시물 관리 API
게시물을 작성, 조회, 수정, 삭제하는 API를 만들어볼게요.
package main
import (
"encoding/json"
"net/http"
"strconv"
)
type Post struct {
ID int `json:"id"`
UserID int `json:"user_id"`
Content string `json:"content"`
}
func createPostHandler(w http.ResponseWriter, r *http.Request) {
var post Post
json.NewDecoder(r.Body).Decode(&post)
err := db.QueryRow("INSERT INTO posts(user_id, content) VALUES($1, $2) RETURNING id", post.UserID, post.Content).Scan(&post.ID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(post)
}
func getPostHandler(w http.ResponseWriter, r *http.Request) {
postID, _ := strconv.Atoi(r.URL.Query().Get("id"))
var post Post
err := db.QueryRow("SELECT id, user_id, content FROM posts WHERE id = $1", postID).Scan(&post.ID, &post.UserID, &post.Content)
if err != nil {
http.Error(w, "게시물을 찾을 수 없습니다", http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(post)
}
// updatePostHandler와 deletePostHandler도 비슷한 방식으로 구현할 수 있어요.
5.5 실시간 채팅 구현
WebSocket을 사용해 실시간 채팅 기능을 구현해볼게요.
package main
import (
"fmt"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
var clients = make(map[*websocket.Conn]bool)
var broadcast = make(chan Message)
type Message struct {
Username string `json:"username"`
Content string `json:"content"`
}
func handleConnections(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
fmt.Println(err)
return
}
defer ws.Close()
clients[ws] = true
for {
var msg Message
err := ws.ReadJSON(&msg)
if err != nil {
delete(clients, ws)
break
}
broadcast <- msg
}
}
func handleMessages() {
for {
msg := <-broadcast
for client := range clients {
err := client.WriteJSON(msg)
if err != nil {
fmt.Printf("error: %v", err)
client.Close()
delete(clients, client)
}
}
}
}
5.6 모든 것을 하나로 합치기
이제 우리가 만든 모든 컴포넌트를 하나의 애플리케이션으로 합쳐볼게요.
package main
import (
"fmt"
"net/http"
)
func main() {
initDB()
http.HandleFunc("/register", registerHandler)
http.HandleFunc("/login", loginHandler)
http.HandleFunc("/post", createPostHandler)
http.HandleFunc("/post/get", getPostHandler)
http.HandleFunc("/ws", handleConnections)
go handleMessages()
fmt.Println("서버가 8080 포트에서 실행 중입니다...")
http.ListenAndServe(":8080", nil)
}
와! 우리가 만든 미니 SNS 서비스를 보세요! 🎉 이 서비스는 사용자 관리, 게시물 관리, 실시간 채팅 기능을 모두 갖추고 있어요. 물론 이 코드는 기본적인 구조만을 보여주는 것이고, 실제 서비스를 위해서는 더 많은 기능과 보안 처리가 필요할 거예요.
🚀 다음 단계: 이 프로젝트를 더 발전시켜보는 건 어떨까요? 예를 들어, 사용자 인증을 위한 JWT 토큰 구현, 파일 업로드 기능 추가, 프론트엔드 개발 등을 해볼 수 있어요!
여러분, 정말 대단해요! 👏 우리는 Go를 사용해 기본적인 네트워크 프로그래밍부터 복잡한 웹 서비스까지 구현해봤어요. 이런 기술들은 재능넷과 같은 플랫폼을 만드는 데 실제로 사용되는 기술들이에요. 여러분이 배운 이 기술들을 활용해 자신만의 독특한 서비스를 만들어보는 건 어떨까요?
Go 언어와 네트워크 프로그래밍의 세계는 정말 넓고 깊어요. 우리가 배운 것은 그 중 일부에 불과해요. 계속해서 학습하고, 실험하고, 새로운 것을 만들어보세요. 여러분의 상상력이 곧 한계예요!
Go의 세계에서 여러분의 모험은 이제 막 시작됐어요. 앞으로 어떤 멋진 프로젝트를 만들어낼지 정말 기대되네요. 화이팅! 🚀