CS/풀스택서비스네트워킹

Socket Programming in C: Client-server example

arsenic-dev 2025. 6. 7. 06:58

Client-server example using TCP

server

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

▶ 헤더파일 포함

int main(void)

▶ main 함수 시작

struct sockaddr_in sa;
int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

▶ 소켓 주소 구조체 생성 + 소켓 생성

  • socket(): 소켓 생성
    • PF_INET: IPv4 프로토콜 사용
    • SCOK_STREAM: TCP 사용
    • IPPROTP_TCP: TCP 프로토콜
  • socket()이 실패하면 -1 반환
if (SocketFD == -1) {
  perror("cannot create socket");
  exit(EXIT_FAILURE);
}

소켓 오류 처리

  • perror: 에러 출력 함수
  • exit(EXIT_FAILURE) == exit(1): 비정상적으로 종료된 프로그램을 에러 로그와 함께 끝냄
memset(&sa, 0, sizeof sa);
sa.sin_family = AF_INET;
sa.sin_port = htons(1100);
sa.sin_addr.s_addr = htonl(INADDR_ANY);

▶ 주소 정보 초기화 및 설정

  • memset: 구조체 sa를 0으로 초기화
  • sin_family: 주소 체계 설정 (IPv4)
  • sin_port: 포트번호 설정 (1100번 포트)
  • sin_addr.s_addr: 어떤 IP에서도 접속 허용
if (bind(SocketFD,(struct sockaddr *)&sa, sizeof sa) == -1) {
  perror("bind failed");
  close(SocketFD);
  exit(EXIT_FAILURE);
}

▶ bind: 소켓에 주소 붙이기

  • 만든 소켓에 IP 주소 + 포트번호를 붙임
  • 실패 시 에러 출력 후 종료
if (listen(SocketFD, 10) == -1) {
      perror("listen failed");
      close(SocketFD);
      exit(EXIT_FAILURE);
    }

▶ listen: 연결 대기 시작

  • 10: 한 번에 10명까지 대기 가능
for (;;) {
  int ConnectFD = accept(SocketFD, NULL, NULL);
 
  if (ConnectFD == -1) {
    perror("accept failed");
    close(SocketFD);
    exit(EXIT_FAILURE);
  }

▶ 무한 루프: 계속 연결 받기

  • accept: 클라이언트 연결 요청을 수락함
    • 연결이 들어올 때까지 기다림 (blocking)
    • 새로 연결된 클라이언트는 ConnectFD로 통신하게 됨
char buffer[256]; // 클라이언트로부터 받을 버퍼
memset(buffer, 0, sizeof(buffer));

ssize_t bytesRead = read(ConnectFD, buffer, sizeof(buffer) - 1); // 읽기

if (bytesRead < 0) {
  perror("read failed");
} 
else {
  printf("Received message: %s\n", buffer); // 받은 메시지 출력

  const char *response = "Message received.\n";
  write(ConnectFD, response, strlen(response)); // 응답 보내기
}

▶ 읽고 씀

if (shutdown(ConnectFD, SHUT_RDWR) == -1) {
        perror("shutdown failed");
        close(ConnectFD);
        close(SocketFD);
        exit(EXIT_FAILURE);
      }
      close(ConnectFD);
    }

▶ 연결 종료 및 클린업

  • shutdown: 읽기쓰기 모두 종료
  • close: 파일 디스크립터(소켓 연결) 닫기
close(SocketFD);
return EXIT_SUCCESS;

▶ 서버 종료 시 메인 소켓도 닫기

 

client

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

▶ 헤더 포함

int main(void)

main 함수

struct sockaddr_in sa;
int res;
int SocketFD;

▶ 변수 선언

  • sa: 접속하려는 서버의 주소 정보
  • res: IP 주소 변환 결과 저장
  • SocketFD: 클라리언트 소켓 식별자
SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (SocketFD == -1) {
  perror("cannot create socket");
  exit(EXIT_FAILURE);
}

▶ 소켓 생성 및 실패 처리

memset(&sa, 0, sizeof sa);
sa.sin_family = AF_INET;
sa.sin_port = htons(1100);
res = inet_pton(AF_INET, "192.168.1.3", &sa.sin_addr);

▶ 서버 주소 초기화 및 설정

  • &sa.sin_addr: 결과가 저장될 곳
  • res가 1이면 성공, 0이면 잘못된 주소, -1이면 오류
if (connect(SocketFD, (struct sockaddr *)&sa, sizeof sa) == -1) {
  perror("connect failed");
  close(SocketFD);
  exit(EXIT_FAILURE);
}

서버 연결 시도

const char *msg = "Hello, server!";
write(SocketFD, msg, strlen(msg));

char buffer[256];
memset(buffer, 0, sizeof buffer);
read(SocketFD, buffer, sizeof buffer - 1);
printf("Received from server: %s\n", buffer);

▶ 통신 부분

close(SocketFD);
return EXIT_SUCCESS;

▶ 소켓 종료

 

Client-server example using UDP

server

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>

헤더파일

int main(void)

 main 함수

int sock;
struct sockaddr_in sa;
char buffer[1024];
ssize_t recsize;
socklen_t fromlen;

변수 선언

  • sock: 소켓 파일 디스크립터 (UDP 소켓용)
  • sa: 클라이언트 주소를 저장할 구조체
  • buffer: 받은 데이터를 저장할 공간 (1024 바이트)
  • recsize: recvfrom()으로 받은 데이터 크기
  • fromlen: 주소 구조체의 크기 (recvfrom()에 필요)
memset(&sa, 0, sizeof sa);
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(7654);
fromlen = sizeof sa;

주소 정보 설정

  • INADDR_ANY: 어떤 IP든 수신하겠다는 의미
  • fromlen: recvfrom() 호출에 필요
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (bind(sock, (struct sockaddr *)&sa, sizeof sa) == -1) {
  perror("error bind failed");
  close(sock);
  exit(EXIT_FAILURE);
}

소켓 생성 및 바인드

  • SOCK_DGRAM: UDP 소켓
for (;;) {
  recsize = recvfrom(sock, (void*)buffer, sizeof buffer, 0, (struct sockaddr*)&sa, &fromlen);

무한 루프: 데이터 받기

  • recvfrom(): client가 보낸 UDP 패킷을 수신하는 함수 (blocking 함수)
  • buffer: 데이터를 저장할 버퍼
  • sa: 보낸 클라이언트 주소 정보 저장
  • fromlen: 주소 구조체 크기
if (recsize < 0) {
  fprintf(stderr, "%s\n", strerror(errno));
  exit(EXIT_FAILURE);
}

오류 처리

  • 수신 실패 시 오류 메시지를 strerror(errno)로 출력하고 종료
printf("recsize: %d\n", (int)recsize);
sleep(1);
printf("datagram: %.*s\n", (int)recsize, buffer);

수신된 데이터 처리

  • 받은 데이터의 길이 출력
  • 1초 기다렸다가
  • 받은 내용을 문자열로 출력

 

client

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>

헤더파일

int main(void)

 main 함수

int sock;
struct sockaddr_in sa;
int bytes_sent;
char buffer[200];

변수 선언

  • sock: 소켓 디스크립터
  • sa: 서버 주소 정보를 저장할 구조체
  • bytes_sent: 실제로 전송한 바이트 수
  • buffer: 보낼 문자열 버
strcpy(buffer, "hello world!");

▶ 보낼 메시지 저장

  • buffer에 문자열 저장
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == -1) {
    printf("Error Creating Socket");
    exit(EXIT_FAILURE);
}

▶ 소켓 생성 및 실패 처리

memset(&sa, 0, sizeof sa);
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr("127.0.0.1");
sa.sin_port = htons(7654);

▶ 서버 주소 설정

  • inet_addr(): 문자열 IP -> 숫자 IP
  • htons: 포트번호를 네트워크 바이트 순서로 변환 (UDP 서버와 같은 포트여야 함)
  bytes_sent = sendto(sock, buffer, strlen(buffer), 0,(struct sockaddr*)&sa, sizeof sa);
  if (bytes_sent < 0) {
    printf("Error sending packet: %s\n", strerror(errno));
    exit(EXIT_FAILURE);
  }

▶ 메시지 전송 및 실패 처리

  • sendto() 함수로 UDP 메시지 전송
    • sock: UDP 소켓
    • buffer: 전송할 데이터
    • strlen(buffer): 데이터 길이
    • 0: 기본 옵션
    • sa: 받을 서버 주소
  • 반환값: 전송된 바이트 수
close(sock);
return 0;

▶ 소켓 종료

 


참고자료

https://en.wikipedia.org/wiki/Berkeley_sockets

 

Berkeley sockets - Wikipedia

From Wikipedia, the free encyclopedia Inter-process communication API A Berkeley (BSD) socket is an application programming interface (API) for Internet domain sockets and Unix domain sockets, used for inter-process communication (IPC). It is commonly impl

en.wikipedia.org

 

'CS > 풀스택서비스네트워킹' 카테고리의 다른 글

Socket Programming in C: Socket API functions  (0) 2025.06.07