
소켓 오류는 네트워크 통신 과정에서 매우 흔하게 발생하는 문제입니다. 연결 설정, 데이터 전송, 연결 종료 등 다양한 단계에서 오류가 나타날 수 있으며, 네트워크 장애, 연결 시간 초과, 시스템 리소스 부족, 잘못된 구성 설정 등 여러 요인이 원인이 됩니다.
이 글에서는 C 언어에서 perror() 함수와 strerror() 함수를 사용해 소켓 오류를 감지하는 두 가지 방법을 예제 코드와 함께 자세히 살펴보겠습니다.
소켓 오류란 무엇인가?
C 언어에서 소켓 오류는 주로 소켓 함수가 반환하는 음수 값이나 특정 오류 코드를 통해 식별됩니다. 이러한 오류 코드는 오류의 성격에 대한 중요한 정보를 제공하므로, 문제를 빠르게 감지하고 해결하는 데 큰 도움이 됩니다. 소켓 함수가 음수를 반환했다면 실행 도중 오류가 발생했다는 뜻입니다. 예를 들어 socket() 함수가 소켓 생성에 실패하면 실패를 나타내는 음수 값을 반환합니다. 반환값을 확인하는 것만으로도 이러한 오류를 손쉽게 감지하고 대응할 수 있습니다.
음수 반환값 외에도 소켓 함수는 전역 변수인 errno를 설정합니다. errno는 가장 최근에 호출된 시스템 또는 라이브러리 함수와 관련된 구체적인 오류 코드를 저장하는 변수로, <errno.h> 헤더 파일을 통해 접근할 수 있습니다. errno에는 오류 원인에 대한 추가 정보를 제공하는 사전 정의된 오류 코드들이 들어 있습니다. 반환값과 오류 코드의 의미를 제대로 이해하면 오류의 발생 지점을 정확히 파악하고 적절한 조치를 취할 수 있습니다.
예제 1: perror() 함수로 소켓 오류 감지하기
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main()
{
int socketDescriptor;
struct sockaddr_in serverAddress;
// 소켓 생성
socketDescriptor = socket(AF_INET, SOCK_STREAM, 0);
if (socketDescriptor < 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 서버 주소 설정
serverAddress.sin_family = AF_INET;
// 예시로 사용할 포트 번호
serverAddress.sin_port = htons(7070);
// 로컬 IP 주소
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
// 서버에 연결 시도
if (connect(socketDescriptor, (struct sockaddr *)&serverAddress,
sizeof(serverAddress)) < 0) {
perror("Connection failed");
exit(EXIT_FAILURE);
}
// 데이터 송수신 수행
// 소켓 닫기
close(socketDescriptor);
return 0;
}
실행 결과:
$ gcc err.c -o err
$ ./err
Connection failed: Connection refused
코드 설명:
이 예제에서는 socket() 함수로 소켓을 생성합니다. 반환된 소켓 디스크립터가 0보다 작으면 소켓 생성 과정에서 오류가 발생한 것이므로, perror() 함수를 호출해 해당 오류 메시지를 출력한 뒤 프로그램을 종료합니다. 이후 서버 주소를 설정하고 connect() 함수를 호출해 연결을 시도하며, 반환값이 0보다 작은지 검사합니다. 연결에 실패하면 perror() 함수로 오류 메시지를 출력하고 프로그램을 종료합니다. 이러한 방식을 사용하면 C 언어에서 소켓 오류를 손쉽게 잡아낼 수 있고, 의미 있는 오류 메시지를 보여주면서 프로그램을 깔끔하게 종료시킬 수 있습니다.
예제 2: strerror() 함수로 소켓 오류 감지하기
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
int main()
{
int socketDescriptor;
struct sockaddr_in serverAddress;
// 소켓 생성
socketDescriptor = socket(AF_INET, SOCK_STREAM, 0);
if (socketDescriptor < 0) {
fprintf(stderr, "Failed to create socket: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
// 서버 주소 설정
serverAddress.sin_family = AF_INET;
// 예시로 사용할 포트 번호
serverAddress.sin_port = htons(7070);
// 로컬 IP 주소
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
// 서버에 연결 시도
if (connect(socketDescriptor, (struct sockaddr *)&serverAddress,
sizeof(serverAddress)) < 0) {
fprintf(stderr, "Failed to connect: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
// 데이터 송수신 수행
// 소켓 닫기
if (close(socketDescriptor) < 0) {
fprintf(stderr, "Socket closure failed: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
printf("Socket closed successfully.\n");
return 0;
}
실행 결과:
$ gcc error.c -o error
$ ./error
Failed to connect: Connection refused
코드 설명:
이 예제에서는 strerror() 함수를 사용해 C 언어의 소켓 오류를 감지합니다. strerror() 함수는 errno 변수에 저장된 오류 코드를 사람이 읽기 쉬운 오류 메시지로 변환해 줍니다. <string.h> 헤더 파일을 포함하면 strerror() 함수를 사용할 수 있으며, errno 값을 인자로 넘겨 해당하는 오류 메시지를 얻을 수 있습니다. 프로그램에서는 소켓을 생성한 뒤 소켓 디스크립터가 0보다 작은지, 즉 생성에 실패했는지 확인합니다. 오류가 발생하면 strerror() 함수에 errno 값을 넘겨 오류 메시지를 가져오고, fprintf() 함수를 통해 표준 에러 스트림(stderr)에 메시지를 출력합니다. 마지막으로 프로그램은 실패 상태로 종료됩니다.
결론
소켓 함수가 제공하는 반환값과 오류 코드의 의미를 이해하면 C 언어에서 소켓 오류를 손쉽게 감지하고 처리할 수 있습니다. 첫 번째 예제에서는 perror() 함수를 사용해 오류를 감지하고 메시지를 출력하는 방법을 살펴보았고, 두 번째 예제에서는 strerror() 함수를 활용해 더 자세한 오류 메시지를 얻는 방법을 알아보았습니다. 이 두 가지 방법을 잘 활용하면 소켓 프로그래밍에서 의미 있는 오류 메시지를 사용자에게 보여주고, 오류 발생 시 프로그램을 안전하게 종료할 수 있습니다.
저자 소개

Bamdeb Ghosh
Bamdeb Ghosh는 무선 네트워킹 분야에서 풍부한 실무 경험을 갖춘 전문가입니다. Wireshark를 활용한 무선 및 유선 네트워크 패킷 캡처 분석 전문가이며, Android, Bluetooth, Linux 명령어, Python에 대한 깊이 있는 지식을 보유하고 있습니다. 그의 사이트 wifisharks.com에서 더 많은 자료를 확인할 수 있습니다.