목차
- TCP 개념에 대한 이전 포스팅
- C 언어 TCP 서버 소켓 예제 이전 포스팅
- TCP 서버 소켓 생성 및 accept 수행 예제
- TCP 클라이언트 소켓 생성 및 서버에 연결 예제
- 클라이언트 소켓 서버에 메세지 전송 예제
- 클라이언트 소켓 서버로부터 메세지 수신 예제
TCP 개념에 대한 이전 포스팅
우선 이전 포스팅과 더불어 서버, 클라이언트 소켓을 생성하여 요청에 응답하는 과정 모두 TCP 프로토콜을 사용하고 있습니다. TCP 프로토콜은 연결지향형 프로토콜로서 메세지의 신뢰성이 우수하고 오류제어, 흐름제어 등의 유용한 기능을 가지고 있습니다. 따라서 이전 포스팅에서 다룬 OSI 7계층 중 TCP 개념에 대해 알아보고 아래의 예제를 학습하는 것이 도움이됩니다.
아래는 OSI 7 계층 관련 포스팅 링크입니다.
2023.08.01 - [자격증/정보처리기사] - [정보처리기사] OSI 7계층 개념 및 각 계층 대표 프로토콜(TCP/IP)
C 언어 TCP 서버 소켓 예제 이전 포스팅
다음으로 오늘 포스팅에서는 TCP 클라이언트 소켓을 생성하여 서버에 연결을 요청하고 메세지를 전송 및 수신할 것입니다. 이를 위해서는 TCP 서버 소켓이 필요합니다. C 언어로 서버를 구성하는 예제는 이전 포스팅에서 다뤘습니다. 아래 링크를 통해 TCP 서버 소켓을 구성하는 방법에 대해 알아보고 예제를 진행해 주세요.
2023.07.13 - [C/응용] - [C언어] 간단한 소켓 프로그래밍 - 1
TCP 서버 소켓 생성 및 accept 수행 예제
우선 아래의 예제처럼 서버 소켓을 생성하여 클라이언트의 요청을 받아들이고 메세지를 수신하고 다시 전송하도록 합니다.
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
int r;
// 서버 소켓 생성
int server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock == -1)
{
printf("socket create error!\n");
return 0;
}
// 서버 주소 구조체 설정
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(9999);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(server_addr.sin_zero, 0, sizeof(server_addr.sin_zero));
// 서버 소켓 바인딩
r = bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (r == -1)
{
printf("bind error!");
return 0;
}
// 서버 소켓 리스닝
r = listen(server_sock, 5);
if (r == -1)
{
printf("listen error!\n");
return 0;
}
// 클라이언트 주소 구조체 설정
struct sockaddr_in client_addr;
socklen_t client_addr_size = sizeof(client_addr);
// 서버 소켓이 클라이언트 연결 요청 수락
int client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_size);
if (client_sock == -1)
{
printf("accept error!\n");
return 0;
}
// 버퍼 설정
char buf[1024];
int buf_size = sizeof(buf);
// 클라이언트 요청 읽기
r = read(client_sock, buf, buf_size);
if (r == -1)
{
printf("read error!\n");
return 0;
}
// 클라이언트 요청 출력
printf("recv msg(from client): %s\n", buf);
// 클라이언트에게 동일한 메세지를 전송
if (send(client_sock, buf, sizeof(buf), 0) == -1) {
printf("전송 실패\n");
}
close(client_sock);
return 0;
}
TCP 클라이언트 소켓 생성 및 서버에 연결 예제
아래는 TCP 클라이언트 소켓을 생성하여 메세지를 전송하는 예제입니다. 서버는 위 예제에서 확인한 로컬의 9999번 포트에 연결합니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main() {
// 소켓 생성
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1) {
printf("소켓 생성 실패");
return 1;
}
// 서버 정보 설정
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(9999);
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
// 서버에 연결
if (connect(clientSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) == -1) {
printf("연결 실패\n");
return 1;
} else {
printf("연결 성공\n");
}
close(clientSocket);
return 0;
}
클라이언트 소켓 서버에 메세지 전송 예제
다음으로 서버에 연결이 성공했다면 메세지를 전송합니다. 메세지는 1024크기의 고정 값을 전송합니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main() {
char message[1024] = "Hello, server!";
// 소켓 생성
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1) {
printf("소켓 생성 실패");
return 1;
}
// 서버 정보 설정
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(9999);
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
// 서버에 연결
if (connect(clientSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) == -1) {
printf("연결 실패");
return 1;
} else {
printf("연결 성공\n");
}
// 메시지 전송
if (send(clientSocket, message, sizeof(message), 0) == -1) {
printf("메시지 전송 실패\n");
return 1;
}
printf("메시지 전송: %s\n", message);
close(clientSocket);
return 0;
}
클라이언트 소켓 서버로부터 메세지 수신 예제
이제 마지막으로 서버가 클라이언트의 메세지를 수신하고 동일한 메세지를 다시 전송한 것을 클라이언트가 수신하는 예제입니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main() {
char message[] = "Hello, server!";
char buffer[1024];
// 소켓 생성
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1) {
perror("소켓 생성 실패");
return 1;
}
// 서버 정보 설정
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(9999);
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
// 서버에 연결
if (connect(clientSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) == -1) {
printf("연결 실패");
return 1;
} else {
printf("연결 성공\n");
}
// 메시지 전송
if (send(clientSocket, message, strlen(message), 0) == -1) {
printf("메시지 전송 실패\n");
return 1;
}
printf("메시지 전송: %s\n", message);
// 서버로부터 메시지 수신
ssize_t bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesRead == -1) {
printf("메시지 수신 실패");
return 1;
}
buffer[bytesRead] = '\0';
printf("서버로부터 수신된 메시지: %s\n", buffer);
// 소켓 종료
close(clientSocket);
return 0;
}