윤성우의 열혈 tcp/ip 소켓프로그래밍을 보며 공부하고 쓰는 블로그
참고로 이 책은 술먹고 쿠팡에서 산건데 여튼 술에 취한내가 저지른 일을 감당하고자 블로깅까지 해본다.
누구 보라고 쓰는건 아니고 나중에 까먹지 말자고 정리 차원에서 쓰는 블로깅이 될 것같다.
이 책의 가장 처음에서는 소켓이 무엇인지, 서버-클라이언트 소켓 통신이 무엇인지 설명하고있다.
그리고 c언어 코드로 구현되고 있는데, 나는 이걸 최대한 golang으로 바꿔서 작성하는식으로 공부해보고자 한다.
먼저 용어 정리
- socket : 서로 멀리 떨어져 있는 host간에 데이터를 주고 받을 수 있도록 네트워크 망에 연결시키는 창구
운영체제에서 제공을 하고 있다.
이 책에서는 socket 통신을 전화기의 작동 원리에 빗대어 표현하고 있다.
1. socket 생성 - 전화기 구입 / 네트워크 통신을 하기 위해 먼저 그 도구인 소켓을 생성한다.
2. bind - 전화번호 할당 / 다른 곳에서 걸려오는 전화를 받기 위해 전화번호 등 정보를 등록하는 행위이다.
네트워크 프로그래밍에서는 ip와 port number를 할당해준다.
3. listen - 연결 요청이 가능한 상태로 만든다. / 전화국에 이제 연결해도 된다고 등록하는 행위라고 생각하면된다.
4. accpet - 연결 요청에 대한 수락 / server(listener) socket은 연결 요청을 수락하고, client socket은 연결 요청을 진행한다.
5. connect - 함수 호출을 통한 서버로의 연결 요청 과정
그리고 이 것을 golang 코드로 구현해보면,
listener socket
func handler(conn net.Conn) {
// 받은 msg 저장할 buffer
recv := make([]byte, 4096)
for {
// read msg from client
n, err := conn.Read(recv)
if err != nil {
if err == io.EOF {
fmt.Println("connection is closed from client : ", conn.RemoteAddr().String())
}
fmt.Println("Failed to receive data : ", err)
break
}
// msg print
if n > 0 {
fmt.Println(string(recv[:n]))
// connection에 보낼 메시지 write
//conn.Write(recv[:n])
}
}
}
func main() {
// socket 생성
listener, err := net.Listen("tcp", ":10000")
if err != nil {
fmt.Println("Failed to Listen : ", err)
}
// 프로세스가 멈추면 listener도 close
defer listener.Close()
// accept
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("Failed to Accept : ", err)
continue
}
// accept 한 후 client에서 받은 메시지 handle
go handler(conn)
}
}
net.Listen 함수로 bind를 해주면서, listen 상태인 socket을 생성한다.
그리고 accept로 connection을 생성하면 이 connection을 통해 전달 받은 데이터를 출력하는 식으로 코드를 구현했다.
client socket
func main() {
// dial & connect to server
conn, err := net.Dial("tcp", ":10000")
if err != nil {
fmt.Println("Failed to Dial : ", err)
}
defer conn.Close()
// go routine 익명함수
go func(c net.Conn) {
// 보낼 메시지
send := "Hello"
for {
// connection에 보낼 메시지 write
_, err = c.Write([]byte(send))
if err != nil {
fmt.Println("Failed to write data : ", err)
break
}
// 1초마다 반복
time.Sleep(time.Second * 1)
}
}(conn)
go func(c net.Conn) {
// connection으로 부터 전달 받은 msg 저장할 buffer
recv := make([]byte, 4096)
for {
// read msg from conn
n, err := c.Read(recv)
if err != nil {
fmt.Println("Failed to Read data : ", err)
break
}
fmt.Println("Recv data : ", string(recv[:n]))
}
}(conn)
// 사용자 입력이 들어올때까지 blocking 했다가 입력을 마치면 서버로 전송
for {
var s string
fmt.Scanln(&s)
conn.Write([]byte(s))
time.Sleep(time.Duration(3) * time.Second)
}
}
listener socket에 dial 한 후 메시지를 1초 간격으로 보내고, 또 서버에서 보낸 데이터를 읽어들이는 코드이다.
일단 이렇게 간단하게 socket 통신을 구현해봤다.
'Golang > etc' 카테고리의 다른 글
tcp/ip 04 (0) | 2022.06.28 |
---|---|
tcp/ip -02,03 (0) | 2022.06.27 |
Golang Apple Login (애플 로그인) (0) | 2022.06.14 |
Apple 로그인 JWT, JWK (1) | 2022.06.14 |
golang .env 파일 환경변수 셋팅 (0) | 2022.04.13 |