본문 바로가기
Developer/C, C++

[C/C++] 네트워크 프로그래밍 (server, client, socket, ...)

by Doony 2021. 9. 9.

기본적인 네트워크 프로그래밍 방식에 대해서는 Beej's Guide to Network Programming을 많이 참조하는 것 같습니다. 홈페이지에 전문이 소개되어 있기도하고, 수 많은 사람들이 Beej의 가이드를 보라고 얘기합니다. 언젠간 저도 정독해보는 걸로...


서버와 클라이언트는 소켓을 통해 통신합니다. 각각의 구동되는 방식에는 아래와 같은 차이점이 있습니다. 그림은 Beej의 가이드에서 퍼왔습니다.


  • socket: 서버와 클라이언트 모두 생성이 필요합니다. 생성되는 소켓을 통해 정보를 주고 받을 수 있습니다.
  • bind : 서버에서 port를 처리하기 위해 필요합니다.
  • connect : 클라이언트에서 서버에 연결하기 위해 필요합니다. 커넥트를 통해 연결 여부를 확인할 수 있습니다.
  • listen : 서버에서 듣는 걸 의미합니다. 즉, 클라이언트 호출이 발생하면, 서버에서 listen을 통해 반응합니다.
  • accept : 서버에서 허용을 확인합니다. 연결이 잘 되었다면 accept를 통해 서버사이드에서 확인합니다.
  • sent, recv : 서버, 클라이언트가 통신하기 위해 자료를 송수신할 때 사용합니다.
  • close : socket을 닫고 통신을 종료할 때 사용합니다.

정리하자면, 서버는 다음 순서를 따릅니다.
socketbindlistenacceptsent, recvclose


클라이언트는 다음 순서를 따릅니다.
socketconnectsend, recvclose


각각의 항목들에 대한 코드는 다음과 같습니다.

socket 생성

1
2
int sock;
sock = socket(PF_INET, SOCK_STREAM,0); // define socket
cs

bind, listen, accept

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int client_sock;
 
struct sockaddr_in serv_addr;
struct sockaddr_in client_addr;
socklen_t client_addr_size;
 
serv_addr.sin_family = AF_INET; 
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(portno);
 
if(bind(sock,(struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1
    printf("bind error\n");
if(listen(sock,5)==-1// Listen
    printf("listen error\n");
 
 
client_sock = accept(sock,(struct sockaddr*)&client_addr,&client_addr_size); 
 
if (client_sock == -1)
  printf("accept error");
cs

눈 여겨봐야할 점은 accept에는 클라이언트 소켓 생성이 필요하다는 점입니다. 또 미리 IPv4, IPv6, 포트넘버 등 프로토콜 정의가 필요합니다.


connect

클라이언트에서 서버 호출 시 필요한 connect는 기본적인 포트 구성은 서버와 동일하며, 아래 코드로 구현합니다.

1
2
if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1)
    printf("connect error\n");
cs

send, recv

send는 말그대로 송신, recv는 receive로 수신을 의미합니다. 서버와 클라이언트에서 둘다 사용할 수 있습니다.

1
2
3
int send(int sockfd, const void *msg, int len, int flags);
int recv(int sockfd, void *buf, int len, int flags);
 
cs

close

소켓 종료 시 사용하며, 간단하게 close(socket) 명령어를 통해 구현합니다. 주의할 점은, 예를 들어 서버에서 send한 뒤 서버를 종료하는 상황을 가정했을 때 send하자마자 종료하면 안된다는 점입니다.


로컬호스트로 구현하면 지장이 없을 수도 있지만, 실제 웹 서버에 올린다고 했을 때는 시간 지연이 발생할 수 있습니다. 즉, 클라이언트가 아직 데이터를 받지 못한 상황에서 서버가 종료될 수도 있기 때문에 그 부분을 주의해야합니다.

댓글