printf("ho_tari\n");
C언어(8) 본문
2025.02.27
큐(QUEUE)
- 먼저 들어온 데이터가 먼저 나가는 자료구조
- 선입선출 (FIFO, First In First Out)
- 예) 매표소의 대기열
큐의 응용
직접적인 응용
- 시뮬레이션의 대기열
- 통신에서의 데이터 패킷들의 모델링에 이용
- 프린터와 컴퓨터 사이의 버퍼링
간접적인 응용
- 스택과 마찬가지로 프로그래머의 도구
- 많은 알고리즘에서 사용됨
선형큐
- 배열을 선형으로 사용하여 큐를 구현
- 삽입을 계속하기 위해서는 요소들을 이동시켜야 함
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MAX_QUEUE_SIZE 5
typedef int element;
typedef struct {
int front;
int rear;
element data[MAX_QUEUE_SIZE];
} QueueType;
void error(char* message) {
fprintf(stderr, "%s\n", message);
exit(1);
}
void init_queue(QueueType* q) {
q->rear = -1;
q->front = -1;
}
void queue_print(QueueType* q) {
for (int i = 0; i < MAX_QUEUE_SIZE; i++)
{
if (i <= q->front || i > q->rear)
{
printf(" | ");
}
else
{
printf("%d | ", q->data[i]);
}
}
printf("\n");
}
int is_full(QueueType* q) {
if (q->rear == MAX_QUEUE_SIZE - 1)
{
return 1;
}
else
{
return 0;
}
}
int is_empty(QueueType* q) {
if (q->front == q->rear)
{
return 1;
}
else
{
return 0;
}
}
void enqueue(QueueType* q, int item) {
if (is_full(q))
{
error("큐가 포화상태입니다.");
return;
}
q->data[++(q->rear)] = item;
}
int dequeue(QueueType* q) {
if (is_empty(q))
{
error("큐가 공백상태입니다.");
return -1;
}
int item = q->data[++(q->front)];
return item;
}
int main(void) {
int item = 0;
QueueType q;
init_queue(&q);
enqueue(&q, 10); queue_print(&q);
enqueue(&q, 20); queue_print(&q);
enqueue(&q, 30); queue_print(&q);
item = dequeue(&q); queue_print(&q);
item = dequeue(&q); queue_print(&q);
item = dequeue(&q); queue_print(&q);
return 0;
}
원형큐(Circular Buffer, Ring Buffer)
공백상태 : front == rear
포화상태 : front % M == (rear + 1) % M
공백상태와 포화상태를 구별하기 위하여 하나의 공간은 항상 비워둔다
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MAX_QUEUE_SIZE 5
typedef int element;
typedef struct {
int front;
int rear;
element data[MAX_QUEUE_SIZE];
} QueueType;
void error(char* message) {
fprintf(stderr, "%s\n", message);
exit(1);
}
void init_queue(QueueType* q) {
q->rear = q->front = 0;
}
void queue_print(QueueType* q) {
printf("QUEUE(front=%d rear=%d) = ", q->front, q->rear);
if (!is_empty(q))
{
int i = q->front;
do {
i = (i + 1) % MAX_QUEUE_SIZE;
printf("%d | ", q->data[i]);
if (i == q->rear) break;
} while (i != q->front);
}
printf("\n");
}
int is_full(QueueType* q) {
return ((q->rear + 1) % MAX_QUEUE_SIZE == q->front);
}
int is_empty(QueueType* q) {
return (q->rear == q->front);
}
void enqueue(QueueType* q, int item) {
if (is_full(q))
{
error("큐가 포화상태입니다.");
return;
}
q->rear = (q->rear + 1) % MAX_QUEUE_SIZE;
q->data[q->rear] = item;
}
element dequeue(QueueType* q) {
if (is_empty(q))
{
error("큐가 공백상태입니다.");
return -1;
}
q->front = (q->front + 1) % MAX_QUEUE_SIZE;
return q->data[q->front];
}
element peek(QueueType* q) {
if (is_empty(q))
{
error("큐가 공백상태입니다.");
return -1;
}
return q->data[(q->front + 1) % MAX_QUEUE_SIZE];
}
int main(void) {
QueueType queue;
int item;
init_queue(&queue);
printf("--데이터 추가 단계--\n");
while (!is_full(&queue))
{
printf("정수를 입력하세요 : ");
scanf("%d", &item);
enqueue(&queue, item);
queue_print(&queue);
}
printf("큐는 포화상태입니다.\n\n");
printf("--데이터 꺼냄 단계--\n");
while (!is_empty(&queue))
{
item = dequeue(&queue);
printf("꺼내온 정수 : %d \n", item);
queue_print(&queue);
}
printf("큐는 공백상태입니다.\n");
return 0;
}
queue.h 헤더 파일
#pragma once
#ifndef __queue_h__
#define __queue_h__
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MAX_QUEUE_SIZE 5
typedef int element;
typedef struct {
int front;
int rear;
element data[MAX_QUEUE_SIZE];
} QueueType;
void init_queue(QueueType* q);
void queue_print(QueueType* q);
void enqueue(QueueType* q, int item);
element dequeue(QueueType* q);
element peek(QueueType* q);
#endif
main.c 파일
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
int main(void) {
QueueType queue;
int element;
init_queue(&queue);
srand(time(NULL)); // 랜덤 함수 초기화(seed 설정)
for (int i = 0; i < 100; i++)
{
if (rand() % 5 == 0)
{
enqueue(&queue, rand() % 100);
}
queue_print(&queue);
if (rand() % 10 == 0)
{
int data = dequeue(&queue);
}
queue_print(&queue);
}
return 0;
}
queue.c 파일
#include "queue.h"
void error(char* message) {
fprintf(stderr, "%s\n", message);
exit(1);
}
void init_queue(QueueType* q) {
q->rear = q->front = 0;
}
void queue_print(QueueType* q) {
printf("QUEUE(front=%d rear=%d) = ", q->front, q->rear);
if (!is_empty(q))
{
int i = q->front;
do {
i = (i + 1) % MAX_QUEUE_SIZE;
printf("%d | ", q->data[i]);
if (i == q->rear) break;
} while (i != q->front);
}
printf("\n");
}
int is_full(QueueType* q) {
return ((q->rear + 1) % MAX_QUEUE_SIZE == q->front);
}
int is_empty(QueueType* q) {
return (q->rear == q->front);
}
void enqueue(QueueType* q, int item) {
if (is_full(q))
{
error("큐가 포화상태입니다.");
return;
}
q->rear = (q->rear + 1) % MAX_QUEUE_SIZE;
q->data[q->rear] = item;
}
element dequeue(QueueType* q) {
if (is_empty(q))
{
error("큐가 공백상태입니다.");
return -1;
}
q->front = (q->front + 1) % MAX_QUEUE_SIZE;
return q->data[q->front];
}
element peek(QueueType* q) {
if (is_empty(q))
{
error("큐가 공백상태입니다.");
return -1;
}
return q->data[(q->front + 1) % MAX_QUEUE_SIZE];
}
실행 결과
덱(deque)
- 덱은 double ended queue의 줄임말
- 큐의 전단(front)과 후단(rear)에서 모두 삽입과 삭제가 가능한 큐
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MAX_QUEUE_SIZE 5
typedef int element;
typedef struct {
int front;
int rear;
element data[MAX_QUEUE_SIZE];
} DequeType;
void error(char* message) {
fprintf(stderr, "%s\n", message);
exit(1);
}
void init_deque(DequeType* q) {
q->rear = q->front = 0;
}
void deque_print(DequeType* q) {
printf("Deque(front=%d rear=%d) = ", q->front, q->rear);
if (!is_empty(q))
{
int i = q->front;
do {
i = (i + 1) % MAX_QUEUE_SIZE;
printf("%d | ", q->data[i]);
if (i == q->rear) break;
} while (i != q->front);
}
printf("\n");
}
int is_full(DequeType* q) {
return ((q->rear + 1) % MAX_QUEUE_SIZE == q->front);
}
int is_empty(DequeType* q) {
return (q->rear == q->front);
}
void add_rear(DequeType* q, int item) {
if (is_full(q))
{
error("큐가 포화상태입니다.");
return;
}
q->rear = (q->rear + 1) % MAX_QUEUE_SIZE;
q->data[q->rear] = item;
}
element delete_front(DequeType* q) {
if (is_empty(q))
{
error("큐가 공백상태입니다.");
return -1;
}
q->front = (q->front + 1) % MAX_QUEUE_SIZE;
return q->data[q->front];
}
element get_front(DequeType* q) {
if (is_empty(q))
{
error("큐가 공백상태입니다.");
return -1;
}
return q->data[(q->front + 1) % MAX_QUEUE_SIZE];
}
void add_front(DequeType* q, element val) {
if (is_full(q))
{
error("큐가 포화상태입니다.");
}
q->data[q->front] = val;
q->front = (q->front - 1 + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE;
}
element delete_rear(DequeType* q) {
int prev = q->rear;
if (is_empty(q))
{
error("큐가 공백상태입니다.");
}
q->rear = (q->rear - 1 + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE;
return q->data[prev];
}
element get_rear(DequeType* q) {
if (is_empty(q))
{
error("큐가 공백상태입니다.");
}
return q->data[q->rear];
}
int main(void) {
DequeType queue;
init_deque(&queue);
for (int i = 0; i < 3; i++)
{
add_front(&queue, i);
deque_print(&queue);
}
for (int i = 0; i < 3; i++)
{
delete_rear(&queue);
deque_print(&queue);
}
return 0;
}
queue.h 헤더파일
#pragma once
#ifndef __queue_h__
#define __queue_h__
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MAX_QUEUE_SIZE 5
//typedef int element;
typedef struct {
int id;
int arrival_time;
int service_time;
} element;
typedef struct {
int front;
int rear;
element data[MAX_QUEUE_SIZE];
} QueueType;
void init_queue(QueueType* q);
void queue_print(QueueType* q);
void enqueue(QueueType* q, element item);
element dequeue(QueueType* q);
element peek(QueueType* q);
#endif
queue.c 파일
#include "queue.h"
void error(char* message) {
fprintf(stderr, "%s\n", message);
exit(1);
}
void init_queue(QueueType* q) {
q->rear = q->front = 0;
}
void queue_print(QueueType* q) {
printf("QUEUE(front=%d rear=%d) = ", q->front, q->rear);
if (!is_empty(q)) {
int i = q->front;
do {
i = (i + 1) % MAX_QUEUE_SIZE;
printf("%d | ", q->data[i]);
if (i == q->rear) break;
} while (i != q->front);
}
printf("\n");
}
int is_full(QueueType* q) {
return ((q->rear + 1) % MAX_QUEUE_SIZE == q->front);
}
int is_empty(QueueType* q) {
return (q->rear == q->front);
}
void enqueue(QueueType* q, element item) {
if (is_full(q)) {
error("큐가 포화상태입니다.");
return;
}
q->rear = (q->rear + 1) % MAX_QUEUE_SIZE;
q->data[q->rear] = item;
}
element dequeue(QueueType* q) {
if (is_empty(q)) {
error("큐가 공백상태입니다.");
return;
}
q->front = (q->front + 1) % MAX_QUEUE_SIZE;
return q->data[q->front];
}
element peek(QueueType* q) {
if (is_empty(q)) {
error("큐가 공백상태입니다.");
return;
}
return q->data[(q->front + 1) % MAX_QUEUE_SIZE];
}
main.c 파일
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
int main(void) {
int minutes = 60;
int total_wait = 0;
int total_customers = 0;
int service_time = 0;
int service_customer;
QueueType queue;
init_queue(&queue);
srand(time(NULL));
for (int clock = 0; clock < minutes; clock++)
{
printf("현재시각 = %d\n", clock);
if ((rand() % 10) < 3)
{
element customer;
customer.id = total_customers++;
customer.arrival_time = clock;
customer.service_time = rand() % 3 + 1;
enqueue(&queue, customer);
printf("고객 %d이 %d분에 들어옵니다. 업무처리시간 = %d분\n", customer.id, customer.arrival_time, customer.service_time);
}
if (service_time > 0)
{
printf("고객 %d 업무처리중입니다. \n", service_customer);
service_time--;
}
else
{
if (!is_empty(&queue))
{
element customer = dequeue(&queue);
service_customer = customer.id;
service_time = customer.service_time;
printf("고객 %d이 %d분에 업무를 시작합니다. 대기시간은 %d분이었습니다.\n", customer.id, clock, clock - customer.arrival_time);
total_wait += clock - customer.arrival_time;
}
}
}
printf("전체 대기 시간 = %d분 \n", total_wait);
return 0;
}
실행 결과
배열 리스트
기본 연산
- 리스트에 새로운 항목 추가 (삽입 연산)
- 리스트에서 항목을 삭제 (삭제 연산)
- 리스트에서 특정한 항목을 찾음 (탐색 연산)
배열을 이용하여 리스트를 구현하면 순차적인 메모리 공간이 할당되므로 이것을 리스트의 순차적 연결이라고 함
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
// 배열을 이용한 리스트의 구성
#define MAX_LIST_SIZE 100
typedef int element;
typedef struct {
element array[MAX_LIST_SIZE]; // 배열 정의
int size; // 현재 리스트에 저장된 항목의 개수
} ArrayListType;
void error(char* message) {
fprintf(stderr, "%s\n", message);
exit(1);
}
void init(ArrayListType* L) {
L->size = 0;
}
int is_empty(ArrayListType* L) {
return L->size == 0;
}
int is_full(ArrayListType* L) {
return L->size == MAX_LIST_SIZE;
}
element get_entry(ArrayListType* L, int pos) {
if (pos < 0 || pos >= L->size)
{
error("위치 오류");
}
return L->array[pos];
}
void print_list(ArrayListType* L) {
int i;
for (i = 0; i < L->size; i++)
{
printf("%d->", L->array[i]);
}
printf("\n");
}
void insert_last(ArrayListType* L, element item) {
if (L->size >= MAX_LIST_SIZE)
{
error("리스트 오버플로우");
}
L->array[L->size++] = item;
}
void insert(ArrayListType* L, int pos, element item) {
if (!is_full(L) && (pos >= 0) && (pos <= L->size))
{
// 뒤에서부터 데이터를 하나씩 뒤로 복사한다.
for (int i = (L->size - 1); i >= pos; i--)
{
L->array[i + 1] = L->array[i];
}
L->array[pos] = item;
L->size++;
}
}
element delete(ArrayListType* L, int pos) {
element item;
if (pos < 0 || pos >= L->size)
{
error("위치 오류");
}
item = L->array[pos];
// 앞에서부터 남은 데이터를 하나씩 앞으로 복사한다.
for (int i = pos; i < (L->size - 1); i++)
{
L->array[i] = L->array[i + 1];
}
L->size--;
return item;
}
int main(void) {
ArrayListType list;
init(&list);
insert(&list, 0, 10); print_list(&list);
insert(&list, 0, 20); print_list(&list);
insert(&list, 0, 30); print_list(&list);
insert_last(&list, 40); print_list(&list);
delete(&list, 0); print_list(&list);
return 0;
}
for문이 아닌 메모리를 이용하여 shift 시키는 방법
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
// 배열을 이용한 리스트의 구성
#define MAX_LIST_SIZE 100
typedef int element;
typedef struct {
element array[MAX_LIST_SIZE]; // 배열 정의
int size; // 현재 리스트에 저장된 항목의 개수
} ArrayListType;
void error(char* message) {
fprintf(stderr, "%s\n", message);
exit(1);
}
void init(ArrayListType* L) {
L->size = 0;
}
int is_empty(ArrayListType* L) {
return L->size == 0;
}
int is_full(ArrayListType* L) {
return L->size == MAX_LIST_SIZE;
}
element get_entry(ArrayListType* L, int pos) {
if (pos < 0 || pos >= L->size)
{
error("위치 오류");
}
return L->array[pos];
}
void print_list(ArrayListType* L) {
int i;
for (i = 0; i < L->size; i++)
{
printf("%d->", L->array[i]);
}
printf("\n");
}
void insert_last(ArrayListType* L, element item) {
if (L->size >= MAX_LIST_SIZE)
{
error("리스트 오버플로우");
}
L->array[L->size++] = item;
}
void insert(ArrayListType* L, int pos, element item) {
if (!is_full(L) && (pos >= 0) && (pos <= L->size))
{
// 뒤에서부터 데이터를 하나씩 뒤로 복사한다.
/*for (int i = (L->size - 1); i >= pos; i--)
{
L->array[i + 1] = L->array[i];
}*/
element tmp[MAX_LIST_SIZE];
memcpy(tmp, L->array, L->size * sizeof(element));
memcpy(&(L->array[pos + 1]), &tmp[pos], (L->size - pos)*sizeof(element));
L->array[pos] = item;
L->size++;
}
}
element delete(ArrayListType* L, int pos) {
element item;
if (pos < 0 || pos >= L->size)
{
error("위치 오류");
}
item = L->array[pos];
// 앞에서부터 남은 데이터를 하나씩 앞으로 복사한다.
/*for (int i = pos; i < (L->size - 1); i++)
{
L->array[i] = L->array[i + 1];
}*/
memcpy(&(L->array[pos]), &(L->array[pos + 1]), (L->size - pos)*sizeof(element));
L->size--;
return item;
}
int main(void) {
ArrayListType list;
init(&list);
insert(&list, 0, 10); print_list(&list);
insert(&list, 0, 20); print_list(&list);
insert(&list, 0, 30); print_list(&list);
insert_last(&list, 40); print_list(&list);
delete(&list, 0); print_list(&list);
return 0;
}
연결 리스트
- 리스트의 항목들을 노드라고 하는 곳에 분산하여 저장
- 노드는 데이터 필드와 링크 필드로 구성
데이터 필드 : 리스트의 원소, 즉 데이터 값을 저장하는 곳
링크 필드 : 다른 노드의 주소값을 저장하는 장소(포인터)
장점
- 삽입, 삭제가 보다 용이하다
- 연속된 메모리 공간이 필요없다
- 크기 제한이 없다
단점
- 구현이 어렵다
- 오류가 발생하기 쉽다
노드 = 데이터 필드 + 링크 필드
단순 연결 리스트
- 하나의 링크 필드를 이용하여 연결
단순 연결 리스트의 연산
- insert_first() : 리스트의 시작 부분에 항목을 삽입하는 함수
- insert() : 리스트의 중간 부분에 항목을 삽입하는 함수
- delete_first() : 리스트의 첫 번째 항목을 삭제하는 함수
- delete() : 리스트의 중간 항목을 삭제하는 함수
- print_list() : 리스트를 방문하여 모든 항목을 출력하는 함수
단순 연결 리스트 삽입 연산 (숫자)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int element;
typedef struct ListNode {
element data;
struct ListNode* link;
} ListNode;
// 오류 메시지를 출력하는 함수
void error(char* message) {
fprintf(stderr, "%d\n", message); // 메시지 출력
exit(1); // 프로그램 종료
}
// 단일 연결 리스트의 첫 번째 위치에 새 노드를 삽입하는 함수
ListNode* insert_first(ListNode* head, int value) {
ListNode* p = (ListNode*)malloc(sizeof(ListNode)); // 새 노드 공간의 동적할당
p->data = value; // 데이터를 저장
p->link = head; // 기존 리스트의 첫 노드를 새 노드의 link로 성정
head = p; // head를 새 노드로 변경
return head;
}
// 특정 위치 (이전 노드 pre 다음)에 새 노드를 삽입하는 함수
ListNode* insert(ListNode* head, ListNode* pre, element value) {
ListNode* p = (ListNode*)malloc(sizeof(ListNode)); // 새 노드 공간의 동적할당
p->data = value; // 데이터를 저장
p->link = pre->link; // 새 노드가 이전 노드의 다음 노드를 가리키도록 설정
pre->link = p; // 이전 노드의 link를 새 노드로 변경
return head;
}
// 리스트의 첫 번째 노드를 삭제하는 함수
ListNode* delete_first(ListNode* head) {
ListNode* removed; // 삭제될 노드
if (head == NULL) return NULL; // 리스트가 비어 있으면 NULL 반환
removed = head; // 삭제할 노드 저장
head = removed->link; // head를 다음 노드로 변경
free(removed); // 삭제된 노드 메모리 해제
return head;
}
// 특정 위치(이전 노드 pre 다음)의 노드를 삭제하는 함수
ListNode* delete(ListNode* head, ListNode* pre) {
ListNode* removed; // 삭제된 노드
removed = pre->link; // 삭제할 노드 지정
pre->link = removed->link; // 이전 노드의 link를 삭제할 노드의 다음 노드로 변경
free(removed); // 삭제된 노드 메모리 해제
return head;
}
// 리스트를 출력하는 함수
void print_list(ListNode* head) {
// head부터 link에 NULL이 보관된 노드까지 반복
for (ListNode* p = head; p != NULL; p = p->link)
{
printf("%d->", p->data); // 노드 데이터 출력
}
printf("NULL\n"); // 노드 리스트의 끝을 표시
}
int main(void) {
ListNode* head = NULL;
for (int i = 0; i < 5; i++)
{
head = insert_first(head, i);
print_list(head);
}
// 2 다음에 99를 삽입
ListNode* pre;
pre = head;
while (pre != NULL && pre->data != 2)
{
pre = pre->link;
}
// 99를 삽입
if (pre != NULL)
{
head = insert(head, pre, 99);
print_list(head);
}
for (int i = 0; i < 5; i++)
{
head = delete_first(head);
print_list(head);
}
return 0;
}
단순 연결 리스트 삽입 연산 (문자열)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// typedef int element; // 정수 저장용 형식 정의
// 문자열 저장용 형식 정의
typedef struct {
char name[100]; // 문자열의 길이가 최대 99
} element;
typedef struct ListNode {
element data;
struct ListNode* link;
} ListNode;
// 오류 메시지를 출력하는 함수
void error(char* message) {
fprintf(stderr, "%d\n", message); // 메시지 출력
exit(1); // 프로그램 종료
}
// 단일 연결 리스트의 첫 번째 위치에 새 노드를 삽입하는 함수
ListNode* insert_first(ListNode* head, element value) {
ListNode* p = (ListNode*)malloc(sizeof(ListNode)); // 새 노드 공간의 동적할당
p->data = value; // 데이터를 저장
p->link = head; // 기존 리스트의 첫 노드를 새 노드의 link로 성정
head = p; // head를 새 노드로 변경
return head;
}
// 특정 위치 (이전 노드 pre 다음)에 새 노드를 삽입하는 함수
ListNode* insert(ListNode* head, ListNode* pre, element value) {
ListNode* p = (ListNode*)malloc(sizeof(ListNode)); // 새 노드 공간의 동적할당
p->data = value; // 데이터를 저장
p->link = pre->link; // 새 노드가 이전 노드의 다음 노드를 가리키도록 설정
pre->link = p; // 이전 노드의 link를 새 노드로 변경
return head;
}
// 리스트의 첫 번째 노드를 삭제하는 함수
ListNode* delete_first(ListNode* head) {
ListNode* removed; // 삭제될 노드
if (head == NULL) return NULL; // 리스트가 비어 있으면 NULL 반환
removed = head; // 삭제할 노드 저장
head = removed->link; // head를 다음 노드로 변경
free(removed); // 삭제된 노드 메모리 해제
return head;
}
// 특정 위치(이전 노드 pre 다음)의 노드를 삭제하는 함수
ListNode* delete(ListNode* head, ListNode* pre) {
ListNode* removed; // 삭제된 노드
removed = pre->link; // 삭제할 노드 지정
pre->link = removed->link; // 이전 노드의 link를 삭제할 노드의 다음 노드로 변경
free(removed); // 삭제된 노드 메모리 해제
return head;
}
// 리스트를 출력하는 함수
void print_list(ListNode* head) {
// head부터 link에 NULL이 보관된 노드까지 반복
for (ListNode* p = head; p != NULL; p = p->link)
{
// printf("%d->", p->data); // 노드 데이터 출력(정수)
printf("%s->", p->data.name); // 노드 데이터 출력(문자열)
}
printf("NULL\n"); // 노드 리스트의 끝을 표시
}
int main(void) {
ListNode* head = NULL;
element data;
strcpy(data.name, "apple");
head = insert_first(head, data);
print_list(head);
strcpy(data.name, "kiwi");
head = insert_first(head, data);
print_list(head);
strcpy(data.name, "banana");
head = insert_first(head, data);
print_list(head);
return 0;
}
단일 연결 리스트 search 알고리즘
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// typedef int element; // 정수 저장용 형식 정의
// 문자열 저장용 형식 정의
typedef struct {
char name[100]; // 문자열의 길이가 최대 99
} element;
typedef struct ListNode {
element data;
struct ListNode* link;
} ListNode;
// 오류 메시지를 출력하는 함수
void error(char* message) {
fprintf(stderr, "%d\n", message); // 메시지 출력
exit(1); // 프로그램 종료
}
// 단일 연결 리스트의 첫 번째 위치에 새 노드를 삽입하는 함수
ListNode* insert_first(ListNode* head, element value) {
ListNode* p = (ListNode*)malloc(sizeof(ListNode)); // 새 노드 공간의 동적할당
p->data = value; // 데이터를 저장
p->link = head; // 기존 리스트의 첫 노드를 새 노드의 link로 성정
head = p; // head를 새 노드로 변경
return head;
}
// 특정 위치 (이전 노드 pre 다음)에 새 노드를 삽입하는 함수
ListNode* insert(ListNode* head, ListNode* pre, element value) {
ListNode* p = (ListNode*)malloc(sizeof(ListNode)); // 새 노드 공간의 동적할당
p->data = value; // 데이터를 저장
p->link = pre->link; // 새 노드가 이전 노드의 다음 노드를 가리키도록 설정
pre->link = p; // 이전 노드의 link를 새 노드로 변경
return head;
}
// 리스트의 첫 번째 노드를 삭제하는 함수
ListNode* delete_first(ListNode* head) {
ListNode* removed; // 삭제될 노드
if (head == NULL) return NULL; // 리스트가 비어 있으면 NULL 반환
removed = head; // 삭제할 노드 저장
head = removed->link; // head를 다음 노드로 변경
free(removed); // 삭제된 노드 메모리 해제
return head;
}
// 특정 위치(이전 노드 pre 다음)의 노드를 삭제하는 함수
ListNode* delete(ListNode* head, ListNode* pre) {
ListNode* removed; // 삭제된 노드
removed = pre->link; // 삭제할 노드 지정
pre->link = removed->link; // 이전 노드의 link를 삭제할 노드의 다음 노드로 변경
free(removed); // 삭제된 노드 메모리 해제
return head;
}
// 리스트를 출력하는 함수
void print_list(ListNode* head) {
// head부터 link에 NULL이 보관된 노드까지 반복
for (ListNode* p = head; p != NULL; p = p->link)
{
// printf("%d->", p->data); // 노드 데이터 출력(정수)
printf("%s->", p->data.name); // 노드 데이터 출력(문자열)
}
printf("NULL\n"); // 노드 리스트의 끝을 표시
}
// 노드값을 탐색하는 함수
ListNode* search_list(ListNode* head, element x) {
ListNode* p = head;
while (p != NULL) // 노드의 끝까지 반복
{
if (strcmp(p->data.name, x.name) == 0) // x와 일치되는 노드 발견
return p; // 발견된 노드 반환
p = p->link; // 다음 노드로 이동
}
return NULL; // 탐색 실패
}
int main(void) {
ListNode* head = NULL;
ListNode* p = NULL;
element data;
element data2;
strcpy(data.name, "apple");
head = insert_first(head, data);
print_list(head);
strcpy(data.name, "kiwi");
head = insert_first(head, data);
print_list(head);
strcpy(data.name, "banana");
head = insert_first(head, data);
print_list(head);
// liwi가 존재하는 노드 찾기
strcpy(data.name, "kiwi");
p = search_list(head, data);
if (p != NULL)
{
strcpy(data2.name, "melon");
insert(head, p, data2);
print_list(head);
}
return 0;
}
두 개의 노드를 하나로 결합
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define USE_NUM
#ifdef USE_NUM
// 정수 저장용 형식 정의
typedef int element;
#else
// 문자열 저장용 형식 정의
typedef struct {
char name[100]; // 문자열의 길이가 최대 99
} element;
#endif
typedef struct ListNode {
element data;
struct ListNode* link;
} ListNode;
// 오류 메시지를 출력하는 함수
void error(char* message) {
fprintf(stderr, "%d\n", message); // 메시지 출력
exit(1); // 프로그램 종료
}
// 단일 연결 리스트의 첫 번째 위치에 새 노드를 삽입하는 함수
ListNode* insert_first(ListNode* head, element value) {
ListNode* p = (ListNode*)malloc(sizeof(ListNode)); // 새 노드 공간의 동적할당
p->data = value; // 데이터를 저장
p->link = head; // 기존 리스트의 첫 노드를 새 노드의 link로 성정
head = p; // head를 새 노드로 변경
return head;
}
// 특정 위치 (이전 노드 pre 다음)에 새 노드를 삽입하는 함수
ListNode* insert(ListNode* head, ListNode* pre, element value) {
ListNode* p = (ListNode*)malloc(sizeof(ListNode)); // 새 노드 공간의 동적할당
p->data = value; // 데이터를 저장
p->link = pre->link; // 새 노드가 이전 노드의 다음 노드를 가리키도록 설정
pre->link = p; // 이전 노드의 link를 새 노드로 변경
return head;
}
// 리스트의 첫 번째 노드를 삭제하는 함수
ListNode* delete_first(ListNode* head) {
ListNode* removed; // 삭제될 노드
if (head == NULL) return NULL; // 리스트가 비어 있으면 NULL 반환
removed = head; // 삭제할 노드 저장
head = removed->link; // head를 다음 노드로 변경
free(removed); // 삭제된 노드 메모리 해제
return head;
}
// 특정 위치(이전 노드 pre 다음)의 노드를 삭제하는 함수
ListNode* delete(ListNode* head, ListNode* pre) {
ListNode* removed; // 삭제된 노드
removed = pre->link; // 삭제할 노드 지정
pre->link = removed->link; // 이전 노드의 link를 삭제할 노드의 다음 노드로 변경
free(removed); // 삭제된 노드 메모리 해제
return head;
}
// 리스트를 출력하는 함수
void print_list(ListNode* head) {
// head부터 link에 NULL이 보관된 노드까지 반복
for (ListNode* p = head; p != NULL; p = p->link)
{
#ifdef USE_NUM
printf("%d->", p->data); // 노드 데이터 출력(정수)
#else
printf("%s->", p->data.name); // 노드 데이터 출력(문자열)
#endif
}
printf("NULL\n"); // 노드 리스트의 끝을 표시
}
// 노드값을 탐색하는 함수
ListNode* search_list(ListNode* head, element x) {
ListNode* p = head;
while (p != NULL) // 노드의 끝까지 반복
{
#ifdef USE_NUM
if (p->data == x)
#else
if (strcmp(p->data.name, x.name) == 0) // x와 일치되는 노드 발견
#endif
return p; // 발견된 노드 반환
p = p->link; // 다음 노드로 이동
}
return NULL; // 탐색 실패
}
// 2개의 노드를 하나로 결합하는 함수 head1 -> head2
ListNode* concat_list(ListNode* head1, ListNode* head2) {
if (head1 == NULL) return head2; // head1이 없으면 head2를 반환
else if (head2 == NULL) return head1; // head1이 있고 head2가 없으면 head1을 반환
else // head1과 head2가 모두 존재하는 경우
{
ListNode* p;
p = head1;
while (p->link != NULL) // head1을 복사한 p가 끝까지 이동(마지막 노드 찾기)
{
p = p->link;
}
p->link = head2;
return head1;
}
}
int main(void) {
ListNode* head1 = NULL;
ListNode* head2 = NULL;
head1 = insert_first(head1, 10);
head1 = insert_first(head1, 20);
head1 = insert_first(head1, 30);
print_list(head1);
head2 = insert_first(head2, 40);
head2 = insert_first(head2, 50);
head2 = insert_first(head2, 60);
print_list(head2);
ListNode* total = concat_list(head1, head2);
print_list(total);
return 0;
}
리스트를 역순으로 변환
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define USE_NUM
#ifdef USE_NUM
// 정수 저장용 형식 정의
typedef int element;
#else
// 문자열 저장용 형식 정의
typedef struct {
char name[100]; // 문자열의 길이가 최대 99
} element;
#endif
typedef struct ListNode {
element data;
struct ListNode* link;
} ListNode;
// 오류 메시지를 출력하는 함수
void error(char* message) {
fprintf(stderr, "%d\n", message); // 메시지 출력
exit(1); // 프로그램 종료
}
// 단일 연결 리스트의 첫 번째 위치에 새 노드를 삽입하는 함수
ListNode* insert_first(ListNode* head, element value) {
ListNode* p = (ListNode*)malloc(sizeof(ListNode)); // 새 노드 공간의 동적할당
p->data = value; // 데이터를 저장
p->link = head; // 기존 리스트의 첫 노드를 새 노드의 link로 성정
head = p; // head를 새 노드로 변경
return head;
}
// 특정 위치 (이전 노드 pre 다음)에 새 노드를 삽입하는 함수
ListNode* insert(ListNode* head, ListNode* pre, element value) {
ListNode* p = (ListNode*)malloc(sizeof(ListNode)); // 새 노드 공간의 동적할당
p->data = value; // 데이터를 저장
p->link = pre->link; // 새 노드가 이전 노드의 다음 노드를 가리키도록 설정
pre->link = p; // 이전 노드의 link를 새 노드로 변경
return head;
}
// 리스트의 첫 번째 노드를 삭제하는 함수
ListNode* delete_first(ListNode* head) {
ListNode* removed; // 삭제될 노드
if (head == NULL) return NULL; // 리스트가 비어 있으면 NULL 반환
removed = head; // 삭제할 노드 저장
head = removed->link; // head를 다음 노드로 변경
free(removed); // 삭제된 노드 메모리 해제
return head;
}
// 특정 위치(이전 노드 pre 다음)의 노드를 삭제하는 함수
ListNode* delete(ListNode* head, ListNode* pre) {
ListNode* removed; // 삭제된 노드
removed = pre->link; // 삭제할 노드 지정
pre->link = removed->link; // 이전 노드의 link를 삭제할 노드의 다음 노드로 변경
free(removed); // 삭제된 노드 메모리 해제
return head;
}
// 리스트를 출력하는 함수
void print_list(ListNode* head) {
// head부터 link에 NULL이 보관된 노드까지 반복
for (ListNode* p = head; p != NULL; p = p->link)
{
#ifdef USE_NUM
printf("%d->", p->data); // 노드 데이터 출력(정수)
#else
printf("%s->", p->data.name); // 노드 데이터 출력(문자열)
#endif
}
printf("NULL\n"); // 노드 리스트의 끝을 표시
}
// 노드값을 탐색하는 함수
ListNode* search_list(ListNode* head, element x) {
ListNode* p = head;
while (p != NULL) // 노드의 끝까지 반복
{
#ifdef USE_NUM
if (p->data == x)
#else
if (strcmp(p->data.name, x.name) == 0) // x와 일치되는 노드 발견
#endif
return p; // 발견된 노드 반환
p = p->link; // 다음 노드로 이동
}
return NULL; // 탐색 실패
}
// 2개의 노드를 하나로 결합하는 함수 head1 -> head2
ListNode* concat_list(ListNode* head1, ListNode* head2) {
if (head1 == NULL) return head2; // head1이 없으면 head2를 반환
else if (head2 == NULL) return head1; // head1이 있고 head2가 없으면 head1을 반환
else // head1과 head2가 모두 존재하는 경우
{
ListNode* p;
p = head1;
while (p->link != NULL) // head1을 복사한 p가 끝까지 이동(마지막 노드 찾기)
{
p = p->link;
}
p->link = head2;
return head1;
}
}
// 리스트를 역순으로 변환
ListNode* reverse(ListNode* head) {
ListNode* p, * q, * r; // 순회 포인터
p = head; // 원래 리스트에서 순차적으로 노드를 탐색하는 포인터
q = NULL; // 현재 처리 중인 노드 (새로운 역순 리스트의 head가 될 노드)
// r은 q의 이전 노드를 저장하는 포인터 (역순 리스트의 이전 head)
while (p != NULL) // 리스트 끝까지 반복
{
r = q; // r은 역순으로 된 리스트
q = p;
p = p->link;
q->link = r; // q링크의 방향 전환
}
return q;
}
int main(void) {
ListNode* head1 = NULL;
ListNode* head2 = NULL;
head1 = insert_first(head1, 10);
head1 = insert_first(head1, 20);
head1 = insert_first(head1, 30);
print_list(head1);
head2 = insert_first(head2, 40);
head2 = insert_first(head2, 50);
head2 = insert_first(head2, 60);
print_list(head2);
ListNode* total = concat_list(head1, head2);
print_list(total);
ListNode* rev = reverse(total);
print_list(rev);
return 0;
}
ethernet 통신
스레드(Thread)
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
#define PORT 8080
#define BUFFER_SIZE 1024
DWORD WINAPI ThreadFunction(LPVOID param);
int main(void) {
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
SOCKET server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE] = { 0 };
char* message = "Hello from server";
// 소켓 설정
server_fd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 소켓 연결
bind(server_fd, (struct sockaddr*)&address, sizeof(address));
listen(server_fd, 3);
printf("서버 대기 중... 포트 : %d\n", PORT);
// 새로운 스레드 생성
HANDLE threads[2];
int threadIDs[2] = { 1, 2 };
for (int i = 0; i < 2; i++)
{
threads[i] = CreateThread(NULL, 0, ThreadFunction, &threadIDs[i], 0, NULL);
if (threads[i] == NULL)
{
printf("스레드 생성 실패\n");
return 1;
}
}
// 스레드 종료 대기
WaitForMultipleObjects(2, threads, TRUE, INFINITE);
// 스레드 핸들 닫기
for (int i = 0; i < 2; i++)
{
CloseHandle(threads[i]);
}
// 접속 대기
new_socket = accept(server_fd, (struct sockaddr*)&address, &addrlen);
// 데이터 수신
while (1)
{
memset(buffer, 0, sizeof(buffer));
recv(new_socket, buffer, BUFFER_SIZE, 0);
printf("클라이언트 : %s\n", buffer);
if (strcmp(buffer, "stop") == 0) break;
}
// 접속 종료
closesocket(new_socket);
closesocket(server_fd);
}
// 송신 스레드
DWORD WINAPI ThreadFunction(LPVOID param) {
int id = *(int*)param;
for (int i = 0; i < 5; i++)
{
printf("Thread %d 실행 중...%d\n", id, i);
Sleep(1000);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <Windows.h>
#pragma comment(lib, "ws2_32.lib")
#define PORT 8080
#define BUFFER_SIZE 1024
DWORD WINAPI thread_tx(LPVOID param);
DWORD WINAPI thread_rx(LPVOID param);
int main(void) {
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
SOCKET server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE] = { 0 };
char* message = "Hello from server";
// 소켓 설정
server_fd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 소켓 연결
bind(server_fd, (struct sockaddr*)&address, sizeof(address));
listen(server_fd, 3);
printf("서버 대기 중... 포트 : %d\n", PORT);
// 새로운 스레드 생성
HANDLE thread_transmit, thread_receive;
thread_transmit = CreateThread(NULL, 0, thread_tx, NULL, 0, NULL);
thread_receive = CreateThread(NULL, 0, thread_rx, NULL, 0, NULL);
if (thread_transmit == NULL) printf("transmit 스레드 생성 실패\n");
if (thread_receive == NULL) printf("receive 스레드 생성 실패\n");
// 접속 대기
new_socket = accept(server_fd, (struct sockaddr*)&address, &addrlen);
// 데이터 수신
while (1)
{
memset(buffer, 0, sizeof(buffer));
recv(new_socket, buffer, BUFFER_SIZE, 0);
printf("클라이언트 : %s\n", buffer);
if (strcmp(buffer, "stop") == 0) break;
}
// 접속 종료
closesocket(new_socket);
closesocket(server_fd);
// 스레드 종료 대기
WaitForMultipleObjects(2, thread_transmit, TRUE, INFINITE);
WaitForMultipleObjects(2, thread_receive, TRUE, INFINITE);
// 스레드 핸들 닫기
CloseHandle(thread_transmit);
CloseHandle(thread_receive);
}
// 송신 스레드
DWORD WINAPI thread_tx(LPVOID param) {
for (int i = 0; i < 5; i++)
{
printf("송신 스레드 실행 중...%d\n", i);
Sleep(1000);
}
return 0;
}
// 수신 스레드
DWORD WINAPI thread_rx(LPVOID param) {
for (int i = 0; i < 5; i++)
{
printf("수신 스레드 실행 중...%d\n", i);
Sleep(800);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <Windows.h>
#pragma comment(lib, "ws2_32.lib")
#define PORT 8080
#define BUFFER_SIZE 1024
DWORD WINAPI thread_tx(LPVOID param);
DWORD WINAPI thread_rx(LPVOID param);
SOCKET new_socket;
typedef enum {
NONE = 0,
RUN,
STOP,
EXIT
} STATE_APP;
STATE_APP stateApp;
int main(void) {
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
SOCKET server_fd;
struct sockaddr_in address;
int addrlen = sizeof(address);
char* message = "Hello from server";
// 소켓 설정
server_fd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 소켓 연결
bind(server_fd, (struct sockaddr*)&address, sizeof(address));
listen(server_fd, 3);
printf("서버 대기 중... 포트 : %d\n", PORT);
// 접속 대기
new_socket = accept(server_fd, (struct sockaddr*)&address, &addrlen);
// 새로운 스레드 생성
HANDLE thread_transmit, thread_receive;
thread_transmit = CreateThread(NULL, 0, thread_tx, NULL, 0, NULL);
if (thread_transmit == NULL) printf("transmit 스레드 생성 실패\n");
thread_receive = CreateThread(NULL, 0, thread_rx, NULL, 0, NULL);
if (thread_receive == NULL) printf("receive 스레드 생성 실패\n");
while (stateApp != EXIT);
// 접속 종료
closesocket(new_socket);
closesocket(server_fd);
// 스레드 종료 대기
WaitForMultipleObjects(1, thread_transmit, TRUE, INFINITE);
WaitForMultipleObjects(1, thread_receive, TRUE, INFINITE);
// 스레드 핸들 닫기
CloseHandle(thread_transmit);
CloseHandle(thread_receive);
}
// 송신 스레드
DWORD WINAPI thread_tx(LPVOID param) {
for (int i = 0; i < 10; i++)
{
printf("송신 스레드 실행 중...%d\n", i);
Sleep(1000);
}
stateApp = EXIT;
return 0;
}
// 수신 스레드
DWORD WINAPI thread_rx(LPVOID param) {
char buffer[BUFFER_SIZE] = { 0 };
// 데이터 수신
while (1)
{
memset(buffer, 0, sizeof(buffer));
recv(new_socket, buffer, BUFFER_SIZE, 0);
printf("클라이언트 : %s\n", buffer);
if (strcmp(buffer, "stop") == 0) break;
}
return 0;
}
서버용
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <Windows.h>
#pragma comment(lib, "ws2_32.lib")
#define PORT 8080
#define BUFFER_SIZE 1024
DWORD WINAPI thread_tx(LPVOID param);
DWORD WINAPI thread_rx(LPVOID param);
SOCKET new_socket;
typedef enum {
NONE = 0,
RUN,
STOP,
EXIT
} STATE_APP;
STATE_APP stateApp;
int main(void) {
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
SOCKET server_fd;
struct sockaddr_in address;
int addrlen = sizeof(address);
char* message = "Hello from server";
// 소켓 설정
server_fd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 소켓 연결
bind(server_fd, (struct sockaddr*)&address, sizeof(address));
listen(server_fd, 3);
printf("서버 대기 중... 포트 : %d\n", PORT);
// 접속 대기
new_socket = accept(server_fd, (struct sockaddr*)&address, &addrlen);
// 새로운 스레드 생성
HANDLE thread_transmit, thread_receive;
thread_transmit = CreateThread(NULL, 0, thread_tx, NULL, 0, NULL);
if (thread_transmit == NULL) printf("transmit 스레드 생성 실패\n");
thread_receive = CreateThread(NULL, 0, thread_rx, NULL, 0, NULL);
if (thread_receive == NULL) printf("receive 스레드 생성 실패\n");
while (stateApp != EXIT);
// 접속 종료
closesocket(new_socket);
closesocket(server_fd);
// 스레드 종료 대기
/*WaitForMultipleObjects(1, thread_transmit, TRUE, INFINITE);
WaitForMultipleObjects(1, thread_receive, TRUE, INFINITE);*/
// 스레드 핸들 닫기
CloseHandle(thread_transmit);
CloseHandle(thread_receive);
}
// 송신 스레드
DWORD WINAPI thread_tx(LPVOID param) {
char txBuffer[80];
for (int i = 0; i < 10; i++)
{
fgets(txBuffer, sizeof(txBuffer), stdin);
if (strncmp(txBuffer, "disconnect", 10) == 0) break;
send(new_socket, txBuffer, strlen(txBuffer), 0);
}
stateApp = EXIT;
return 0;
}
// 수신 스레드
DWORD WINAPI thread_rx(LPVOID param) {
char buffer[BUFFER_SIZE] = { 0 };
// 데이터 수신
while (1)
{
memset(buffer, 0, sizeof(buffer));
recv(new_socket, buffer, BUFFER_SIZE, 0);
if (stateApp == EXIT) break;
printf("클라이언트 : %s\n", buffer);
if (strcmp(buffer, "stop") == 0) break;
}
return 0;
}
클라이언트용
#include <WinSock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
#define IS_CLIENT
#define SERVER_IP "127.0.0.1"
#define PORT 8080
#define BUFFER_SIZE 1024
DWORD WINAPI thread_tx(LPVOID param);
DWORD WINAPI thread_rx(LPVOID param);
SOCKET sock, new_socket;
typedef enum {
NONE = 0,
RUN,
STOP,
EXIT
} STATE_APP;
STATE_APP stateApp;
int main(void) {
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
struct sockaddr_in address;
int addrlen = sizeof(address);
// 소켓 설정
sock = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_port = htons(PORT);
#ifdef IS_CLIENT
//address.sin_addr.s_addr = inet_addr(SERVER_IP);
if (inet_pton(AF_INET, SERVER_IP, &address.sin_addr) != 1) {
printf("inet_pton 변환 실패! 잘못된 IP 주소: %s\n", SERVER_IP);
return 1;
}
#else
address.sin_addr.s_addr = INADDR_ANY;
#endif
// 소켓 연결
#ifdef IS_CLIENT
connect(sock, (struct sockaddr*)&address, sizeof(address));
#else
bind(sock, (struct sockaddr*)&address, sizeof(address));
listen(sock, 3);
printf("서버 대기 중... 포트 : %d\n", PORT);
// 접속 대기(waiting...)
new_socket = accept(sock, (struct sockaddr*)&address, &addrlen);
#endif
// 새로운 스레드 생성
HANDLE thread_transmit, thread_receive;
thread_transmit = CreateThread(NULL, 0, thread_tx, NULL, 0, NULL);
if (thread_transmit == NULL) printf("transmit 스레드 생성 실패\n");
thread_receive = CreateThread(NULL, 0, thread_rx, NULL, 0, NULL);
if (thread_receive == NULL) printf("receive 스레드 생성 실패\n");
while (stateApp != EXIT);
// 접속 종료
closesocket(new_socket);
closesocket(sock);
// 스레드 종료 대기
//WaitForMultipleObjects(1, thread_transmit, TRUE, INFINITE);
//WaitForMultipleObjects(1, thread_receive, TRUE, INFINITE);
// 스레드 핸들 닫기
CloseHandle(thread_transmit);
CloseHandle(thread_receive);
}
// 송신 스레드
DWORD WINAPI thread_tx(LPVOID param) {
char txBuffer[80];
while (1) {
fgets(txBuffer, sizeof(txBuffer), stdin);
if (strncmp(txBuffer, "disconnect", 10) == 0)
break;
#ifdef IS_CLIENT
send(sock, txBuffer, strlen(txBuffer), 0);
#else
send(new_socket, txBuffer, strlen(txBuffer), 0);
#endif
}
stateApp = EXIT;
return 0;
}
// 수신 스레드
DWORD WINAPI thread_rx(LPVOID param) {
char buffer[BUFFER_SIZE] = { 0 };
// 데이터 수신
while (1) {
memset(buffer, 0, sizeof(buffer));
#ifdef IS_CLIENT
recv(sock, buffer, BUFFER_SIZE, 0);
#else
recv(new_socket, buffer, BUFFER_SIZE, 0);
#endif
if (stateApp == EXIT) break;
printf("클라이언트 : %s\n", buffer);
if (strcmp(buffer, "stop") == 0) break;
}
return 0;
}