반응형

 

1. BeautifulSoup

 

BeautifulSoup 라이브러리에서는 웹사이트에 데이터를 읽어와서 파싱할 수 있는 기능을 제공하고 있다.

import requests
from bs4 import BeautifulSoup

def get_fear_and_greed():
    url = "https://edition.cnn.com/markets/fear-and-greed"
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    # HTML 구조에 맞는 특정 요소를 찾아 Fear and Greed Index 값을 추출
    index = soup.find("div", class_="fear-and-greed-index").text.strip()
    return index

if __name__ == "__main__":
    index_value = get_fear_and_greed()
    print(f"CNN Fear and Greed Index: {index_value}")

 

 

하지만 아래 코드를 수행해보면 정상적으로 데이터를 파싱하지 못하는 것 처럼 보일 것이다.

(특히 직접 원하는 영역의 div의 class이름을 검색해보면 결과가 포함이 되지 않을 것이다.)

 

2. Selenium

그 이유는 해당 값이 JavaScript로 동적으로 로딩되기 때문이다. requests와 BeautifulSoup은 HTML 소스를 바로 가져오기 때문에 JavaScript로 생성된 콘텐츠는 포함되지 않는다.

 

이 문제를 해결하려면, Selenium과 같은 브라우저 자동화 도구를 사용하여 동적으로 로딩되는 콘텐츠를 포함한 페이지를 가져올 수 있다. Selenium을 사용하면 JavaScript가 로드된 후 페이지에서 데이터를 추출할 수 있다.

 

from selenium import webdriver
from selenium.webdriver.common.by import By

url = "https://edition.cnn.com/markets/fear-and-greed"

# 브라우저를 실행합니다.
driver = webdriver.Chrome()

driver.get(url)

# 원하는 div를 찾습니다.
index_value = driver.find_element(By.CLASS_NAME, "market-fng-gauge__dial-number").text
print(f"CNN Fear and Greed Index: {index_value}")

# 브라우저 종료
driver.quit()

 

 

이때 매 실행마다 url에 해당하는 사이트가 열리고 켜지면서 실행시간이 아주 오래 걸리는 것을 확인할 수 있다.

 

3. 시간 단축

실제로 데이터를 동적로딩해야하기 때문에 이는 어쩔 수 없는 방법이다. 하지만 시간 단축을 위해서 몇가지 추가할 수 있는 옵션이 있다.

 

Seleniumheadless 모드를 사용해 브라우저 창을 열지 않고 백그라운드에서 동작하도록 할 수 있다. 이렇게 하면 화면에 표시되는 부분을 렌더링하지 않아서 속도가 빨라진다.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options

url = "https://edition.cnn.com/markets/fear-and-greed"

# Chrome 옵션 설정 (headless 모드)
chrome_options = Options()
chrome_options.add_argument("--headless")  # 화면을 표시하지 않음

# 브라우저를 headless 모드로 실행
driver = webdriver.Chrome(options=chrome_options)

driver.get(url)

# 원하는 div를 찾습니다.
index_value = driver.find_element(By.CLASS_NAME, "market-fng-gauge__dial-number").text
print(f"CNN Fear and Greed Index: {index_value}")

# 브라우저 종료
driver.quit()

 

 

4. api를 활용하자

그렇지만 실제로 동적으로 데이터를 받아와야 하는 입장이기 때문에 속도저하는 불가피하다.

이를 개선하기 위해서 다양한 api를 활용해야한다.

 

만약에 미국 주식 지수와 관련한 데이터라면 yfinance 라이브러리를 통해서 데이터를 제공받을 수 있다.

pip install yfinance

 

기본 예시 코드

import yfinance as yf

# VIX 지수 티커
vix = yf.Ticker("^VIX")

# 최근 종가 데이터 가져오기
vix_data = vix.history(period="1d")
print("VIX 지수:", vix_data["Close"].iloc[-1])

 

 

웹크롤링과 라이브러리를 함께 사용한 예시 코드

import sys
import requests
import yfinance as yf
import matplotlib.pyplot as plt
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel
from PyQt6.QtCore import Qt
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas

class DataFetcher:
    """데이터를 가져오는 클래스 (웹 크롤링 또는 API)"""

    @staticmethod
    def fetch_fear_greed_index():
        """CNN Fear & Greed Index 크롤링"""
        chrome_options = Options()
        chrome_options.add_argument("--headless")
        chrome_options.add_argument("--ignore-certificate-errors")

        driver = webdriver.Chrome(options=chrome_options)
        driver.get("https://edition.cnn.com/markets/fear-and-greed")

        index_value = driver.find_element(By.CLASS_NAME, "market-fng-gauge__dial-number").text
        driver.quit()

        return f"CNN Fear & Greed Index: {index_value}"

    @staticmethod
    def fetch_vix_data():
        """VIX 지수 데이터 가져오기 (지난 1개월)"""
        vix = yf.Ticker("^VIX")
        vix_data = vix.history(period="1mo")
        return vix_data

class MarketIndexApp(QWidget):
    """GUI를 관리하는 클래스"""

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Market Index Dashboard")
        self.resize(500, 400)

        self.layout = QVBoxLayout()
        
        self.fear_greed_label = QLabel("Loading Fear & Greed Index...", self)
        self.fear_greed_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.layout.addWidget(self.fear_greed_label)

        self.vix_label = QLabel("Loading VIX Index...", self)
        self.vix_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.layout.addWidget(self.vix_label)

        # 그래프 추가
        self.figure, self.ax = plt.subplots(figsize=(5, 3))
        self.canvas = FigureCanvas(self.figure)
        self.layout.addWidget(self.canvas)

        self.setLayout(self.layout)

        self.update_data()

    def update_data(self):
        """데이터를 가져와 UI에 표시"""
        self.fear_greed_label.setText(DataFetcher.fetch_fear_greed_index())

        vix_data = DataFetcher.fetch_vix_data()
        self.vix_label.setText(f"VIX 지수 (최신값): {vix_data['Close'].iloc[-1]:.2f}")

        # 그래프 업데이트
        self.ax.clear()
        self.ax.plot(vix_data.index, vix_data["Close"], marker='o', linestyle='-', color='b', label="VIX Close")
        self.ax.set_title("VIX Index Trend (Last 1 Month)")
        self.ax.set_xlabel("Date")
        self.ax.set_ylabel("VIX Value")
        self.ax.legend()
        self.ax.grid(True)

        self.canvas.draw()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MarketIndexApp()
    window.show()
    sys.exit(app.exec())
반응형
반응형

 

사실 chat gpt 에게 물어보면서 진행하면 더 편하지만, 작업 환경 셋팅을 위한 전반적인 그림이 필요하신 분이 있을 것 같아 글을 남깁니다. ㅎㅎ

 

 

1. python 설치 

 

직접 python 사이트에서 설치해도 되지만, 윈도우 작업 환경이시라면, MS store에서 python을 설치하는 것 만으로 

python 설치 & 환경변수 설정이 한번에 가능합니다.

 

 

여러가지 python 버전이 있는데, 그냥 아무거나 설치하셔도 됩니다.

사용하실 대부분의 기능들은 python3이상이라면 정상 동작 할 것이기 때문에...

 

 

2. VS code 설치 

 

아래 사이트에서 vsc 코드를 다운 받으시고 실행시키면 됩니다.

https://code.visualstudio.com/download

 

Download Visual Studio Code - Mac, Linux, Windows

Visual Studio Code is free and available on your favorite platform - Linux, macOS, and Windows. Download Visual Studio Code to experience a redefined code editor, optimized for building and debugging modern web and cloud applications.

code.visualstudio.com

 

 

vsc에서 python 개발을 위한 플러그인을 설치해야하는데, 아래처럼 python extensions을 설치해주시면 됩니다. 

 

 

3. 가상 환경 설정 

 

작업할 test.py 파일 하나 만드시고 terminal에 가상환경 생성을 위한 명령어를 입력

python -m venv venv  # 가상환경 생성

 

 

그리고 가상환경 활성화를 위해서 아래 명령어를 입력

source venv/bin/activate  # (Mac/Linux) 활성화
venv\Scripts\activate  # (Windows) 활성화

 

간혹 아래 처럼 문제가 발생하는 경우가 있다.

 

단순히 power shell이 관리자 권한이 아니기에 발생하는 문제이기 때문에 아래 명령어를 입력하여 관리자 권한의 terminal로 변경해주면 된다.

 

 Set-ExecutionPolicy Unrestricted -Scope Process

 

 

그러면 아래 사진 처럼 teminal command 창 옆에 (venv)이라고 가상환경이 활성화 된 것을 확인할 수 있다.

 

 

4. PyQt 및 필수 패키지 설치

 

 

pip install PyQt6 pyqt6-tools


PyQt6: PyQt 프레임워크
pyqt6-tools: Qt Designer, uic(코드 변환기) 등 포함

 

5. 코드 작성

 

아래 처럼 기본 코드를 작성

Run - start debuging을 수행하면 창 하나가 나온다.

import sys
from PyQt6.QtWidgets import QApplication, QWidget

class MyApp(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("My PyQt App")  # 창 제목 설정
        self.resize(400, 300)  # 창 크기 설정 (가로x세로)
        self.show()  # 창 표시

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MyApp()
    sys.exit(app.exec())  # 앱 실행

 

 

 

6. 사실 ui 작업이 많아지면 gt designer를 통해서 ui를 만드는게 효율적입니다.

https://jeongbang.tistory.com/3

 

VSCode 에서 PyQt5를 이용한 GUI 만들기

PyQt5를 이용해 파이썬 GUI 프로그래밍을 해보도록 하겠습니다. 파이썬 개발환경이 구성되어 있다는 가정하에 진행하도록 하겠습니다. VSCode에서 Python 개발환경 구성하기 파이썬 IDE에는 여러가지

jeongbang.tistory.com

 

반응형
반응형

c++에서는 new 키워드를 사용해서 동적으로 메모리를 할당합니다.

그리고 이러한 메모리는 반드시 delete 키워드를 사용하여 메모리 할당을 해제합니다.

 

스마트 포인터(smart pointer)란 포인터처럼 동작하는 클래스 템플릿으로, 사용이 끝난 메모리를 자동으로 해제해 줍니다.

 

java에서의 가비지 컬렉션과 같은 역할을 해주는 것입니다.

 

C++11 이전에는 auto_ptr이라는 스마트 포인터를 사용하여 이 작업을 수행하였습니다.

하지만 C++11부터는 다음과 같은 새로운 스마트 포인터를 제공하고 있습니다.

 

  •  unique_ptr
  •  shared_ptr
  •  weak_ptr

 

1. unique_ptr 

 

하나의 스마트 포인터만 특정 객체를 소유하는 것입니다. 해당 스마트 포인터는 move 함수를 통해서 소유권을 이전할  수는 있지만 복사는 불가능합니다.

 

unique_ptr<int> ptr01(new int(5)); // int형 unique_ptr인 ptr01을 선언하고 초기화함.

auto ptr02 = move(ptr01);          // ptr01에서 ptr02로 소유권을 이전함.

// unique_ptr<int> ptr03 = ptr01;  // 대입 연산자를 이용한 복사는 오류를 발생시킴. 

ptr02.reset();                     // ptr02가 가리키고 있는 메모리 영역을 삭제함.

ptr01.reset();                     // ptr01가 가리키고 있는 메모리 영역을 삭제함.

 

 

예시코드입니다.

#include <iostream>

#include <memory>

using namespace std;

 

class Person

{

private:

    string name_;

    int age_;

public:

    Person(const string& name, int age); // 기초 클래스 생성자의 선언

    ~Person() { cout << "소멸자가 호출되었습니다." << endl; }

    void ShowPersonInfo();

};

 

int main(void)

{

    unique_ptr<Person> hong = make_unique<Person>("길동", 29);

    hong->ShowPersonInfo();

    return 0;

}

 

Person::Person(const string& name, int age) // 기초 클래스 생성자의 정의

{

    name_ = name;

    age_ = age;

    cout << "생성자가 호출되었습니다." << endl;

}

 

void Person::ShowPersonInfo() { cout << name_ << "의 나이는 " << age_ << "살입니다." << endl; }

 

실행 결과입니다.

 

생성자가 호출되었습니다.

길동의 나이는 29살입니다.

소멸자가 호출되었습니다.

 

 

자동으로 메모리를 해제해주기 때문에 개발자가 메모리에 대한 신경을 덜 써줘도 되는 장점이 있습니다.

 

2. shared_ptr

 

하나의 특정 객체를 참조하는 스마트 포인터가 총 몇 개인지 참조하는 스마트 포인터입니다.

 

아래는 예시 코드입니다.

shared_ptr<int> ptr01(new int(5)); // int형 shared_ptr인 ptr01을 선언하고 초기화함.

cout << ptr01.use_count() << endl; // 1

auto ptr02(ptr01);                 // 복사 생성자를 이용한 초기화

cout << ptr01.use_count() << endl; // 2

auto ptr03 = ptr01;                // 대입을 통한 초기화

cout << ptr01.use_count() << endl; // 3  

make_shared() 함수를 사용하면 shared_ptr 인스턴스를 안전하게 생성할 수 있습니다.

 

예시 코드입니다.

shared_ptr<Person> hong = make_shared<Person>("길동", 29);

cout << "현재 소유자 수 : " << hong.use_count() << endl; // 1

auto han = hong;

cout << "현재 소유자 수 : " << hong.use_count() << endl; // 2

han.reset(); // shared_ptr인 han을 해제함.

cout << "현재 소유자 수 : " << hong.use_count() << endl; // 1

 

3. weak_ptr 

 

하나 이상의 shared_ptr 인스턴스가 소유하는 개체에 대한 접근을 제공하지만 소유자의 수에는 포함되는 않는 스마트 포인터입니다.

 

 

4. enable_shared_from_this

 

 이 친구는 아래와 같은 형태로 사용된다.

class type : public std::enable_shared_from_this<type>
{
public:
    type(){ std::cout << __FUNCTION__ << std::endl;}
    ~type(){ std::cout << __FUNCTION__ << std::endl;}
     
    std::shared_ptr<type> getPtr()
    {
        //return std::shared_ptr<type>(this);
        return shared_from_this();
    }   
};


 

정상적인 동작을 위해서 사용한다.

 

아래코드를 보자

#include <iostream>
#include <memory>
 
class type
{
public:
    type(){ std::cout << __FUNCTION__ << std::endl;}
    ~type(){ std::cout << __FUNCTION__ << std::endl;}
     
    std::shared_ptr<type> getPtr()
    {
        return std::shared_ptr<type>(this);
    }   
};
 
int main()
{
    type *p = new type;
     
    std::shared_ptr<type> ptr1(p); //p object를 가르키는 shared_ptr 생성자 호출
    std::cout <<"ptr1.use_count(): " << ptr1.use_count() << std::endl;
 
    // ptr2에 ptr1에서 객체의 주소를 return 받아 할당한다.
    std::shared_ptr<type> ptr2 = ptr1->getPtr();
    std::cout <<"ptr2.use_count(): " << ptr2.use_count() << std::endl;
     
    return 0;
}


 

type이라는 클래스 하나를 동적선언하고 ptr1에 할당한다. 그리고 ptr1이 사용되지 않기에 메모리를 소멸시키게 되는데 그렇기 때문에 ptr2에서는 오류가 발생한다. (Segmentation fault) 

 

이를 방지하고자 사용된다.

 

#include <iostream>
#include <memory>
 
class type : public std::enable_shared_from_this<type>
{
public:
    type(){ std::cout << __FUNCTION__ << std::endl;}
    ~type(){ std::cout << __FUNCTION__ << std::endl;}
     
    std::shared_ptr<type> getPtr()
    {
        //return std::shared_ptr<type>(this);
        return shared_from_this();
    }   
};
 
int main()
{
    type *p = new type;
     
    std::shared_ptr<type> ptr1(p); //p object를 가르키는 shared_ptr 생성자 호출
    std::cout <<"ptr1.use_count(): " << ptr1.use_count() << std::endl;
 
    // ptr2에 ptr1에서 객체의 주소를 return 받아 할당한다.
    std::shared_ptr<type> ptr2 = ptr1->getPtr();
    std::cout <<"ptr2.use_count(): " << ptr2.use_count() << std::endl;
     
    return 0;
}

 

shared_ptr을 추가할 경우에는 std::enable_shared_from_this 클래스로부터 상속을 받게되는 구조이다.

 

출처: www.tcpschool.com/cpp/cpp_template_smartPointer
출처: https://chipmaker.tistory.com/entry/enablesharedfromthis-정리 [CHIPMAKER]

반응형
반응형

TCP 패킷의 특징은 데이터에 대해서 1. 연결지향성 2. 신뢰성 보장이 있습니다. 

무조건 데이터를 상대방에게 전송합니다. 하지만 받는 쪽에서 전체 데이터를 못받을 수 있다는 문제점이 있습니다.

 

아래는 대표적인 client.cpp 코드입니다.

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

#define MAXLINE 1024 //buf 크기
#define TOTALFORK 5 //클라이언트 수

void createClient(char *port, char *serverIP);
int main(int argc, char *argv[]) {
	if(argc != 3) {
		printf("Use %s ip_addr port\n", argv[0]);
		exit(0);
	}

	pid_t pids[TOTALFORK]; //client fork
	int runProcess = 0;
	
	while(runProcess < TOTALFORK) {
		sleep(1);
		pids[runProcess] = fork();

		if(pids[runProcess] < 0) {
			return -1;
		}
		
		if(pids[runProcess] == 0) {
			createClient(argv[2], argv[1]);
			exit(0);
		} else { //부모 프로세스
			printf("parent %ld, child %ld\n", (long)getpid(), (long)pids[runProcess]);
		}
		runProcess++;
	}
	return 0;
}

void createClient(char *port, char *serverIP) {
	struct sockaddr_in servaddr;
	int strlen = sizeof(servaddr);
	int sockfd, buf, cNum;//cNum 연결 번호

	if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
		perror("socket fail");
		exit(0);
	}

	memset(&servaddr, 0, strlen);
	servaddr.sin_family = AF_INET;
	inet_pton(AF_INET, serverIP, &servaddr.sin_addr);
	servaddr.sin_port = htons(atoi(port));

	if(connect(sockfd, (struct sockaddr *)&servaddr, strlen) < 0) {
		perror("connect fail");
		exit(0);
	}
	
	srand((unsigned)time(NULL));
	buf = rand() % 100 + 1; //rand 값 생성
	write(sockfd, &buf, 4); //server로 전송
	printf("cleint value : %d\n", buf);
	read(sockfd, &buf, 4); //server에서 받아 옴
	printf("Server sum result : %d\n", buf);
	close(sockfd);
}

 

네트워크 상태에 따라서 패킷이 찢어져서 들어오게 된다면 어떻게 될까요

정답은 짤린 패킷이 여러번에 걸쳐서 입력되는 형태 입니다. 

 

이러한 문제를 해결하기 위해서 while루프, length, offset을 사용해야합니다.

아래 처럼 offset과 length를 통해서 받은 만큼 표시를 해주며, 원하는 크기까지 받도록 무한 루프를 구성해야 합니다.

 int length = sizeof(Data) + strlen(name_msg);  //
 int offset = 0;
        while(1){
            int n = send(sock, data + offset, length, 0);

            if(n == -1){
                if(errno == EINTR) // signal interrupted
                    continue;
                else if(errno == EBADF)
                    cout<< "reject in network"<<endl;
                else if(errno == ENOTSOCK)
                    cout<< "sock err"<<endl;

                return (void*) - 1;
             }
            offset += n;
            length -= n;
            if(length == 0)
                break;
            
        }

 

그렇기 때문에 만약 서버라면 클라이언트별로 버퍼를 구성해주어야 합니다. 

 

 

아래 링크도 참고하세요.

stackoverflow.com/questions/43759231/sending-and-receiving-all-data-c-sockets

 

Sending and receiving all data (C++ sockets)

Help me please to find out what is wrong in client-server communication... The client sends to server jpeg frames from camera 25 times per second using this function: int SendAll(SOCKET &

stackoverflow.com

근데 이때, 구조체가 가변길이이고, 패킷 헤더에서 패킷의 길이를 전달해주는 구조라면 구현이 더욱 복잡해집니다. 

실제 이렇게 세세한 부분까지는 자료도 거의 없어서 직접 구현을 해야한다는 어려움이 있습니다. 

반응형
반응형

선언해야할 헤더는 2가지입니다.

 

#include <unistd.h> 
#include <fcntl.h> 

 

리눅스에서는 모든것을 파일형태로 관리합니다. 소켓또한 파일디스크립터 번호를 부여하고 관리합니다.

파일에 대한 속성을 변경하거나 얻어올 때 사용하는 함수가 바로 fnctl입니다.

 

 

int fcntl(int fd, int cmd, ... /* arg */ );

형태로 사용합니다.

반환값은 cmd에 따라 다르고 실패한다면 -1을 전달합니다.

 

아래는 커맨드입니다.

 

 

아래 코드는 논블록킹 구현을 위한 예제입니다.

 

 

위와같이 함수를 호출하고, 서버와 클라이언트에 대한 소켓이 생성될때 해당 함수를 호출해주면 되는 구조입니다.

반응형
반응형

위와 같은 형태를 가지고 있죠.

가변길이 구조체란 배열의 크기를 동적으로 할당하여 사용하는 것이다.

 

 

이때 2가지를 지켜야한다.

 

  • 1. 사이즈가 0인 array는 가장 아래에 선언해야한다.
  • 2. 동적할당을 하고 사용해야 한다.

동적할당하는 방법이나, 세부적인 내용은 아래 링크들을 참고하시면 감이 올거다.

 

 

그리고 논란인 char name[0] char name[]의 차이점은 

즉, 같은 문법으로 사용되고 있고, 표준은 []이 정확하다는 의견이다. c99 이후 버전을 사용한다면 []를 지향하자.

 

 

 

 

 

computersource.tistory.com/61blog.naver.com/PostView.nhn?blogId=sdi760210&logNo=70084541983&parentCategoryNo=63&viewDate=&currentPage=1&listtype=0

 

가변길이 구조체(flexible array member)

커널 코드를 살펴보다, 아래 예제와 같이 struct 선언 마지막에 size가 0인 array를 선언하는 코드를 발견하였다. 1 2 3 4 5 6 7 struct account {     int age;     int gender;     int name_..

computersource.tistory.com

blog.naver.com/PostView.nhn?blogId=sdi760210&logNo=70084541983&parentCategoryNo=63&viewDate=&currentPage=1&listtype=0

 

가변길이 구조체 벰버(Flexible Array Member )

--- 읽기전 당부사항 --- 나름 자료를 찾고 이해해서 올린 자료입니다. 혹시나 틀리게 있다면 뭐 이런게 다...

blog.naver.com

 

www.forbes.com/sites/quora/2013/05/14/what-is-the-advantage-of-using-zero-length-arrays-in-c/?sh=660c8a2f213a

반응형
반응형

네트워크 소켓통신시에는 패킹이라는 것을 해야합니다.

 

우선, 왜써야 할까?

 

 

해당 구조체에서 Data 구조체의 크기는?    data[0]는 단순히 메모리 위치만은 가르키는 녀석이기 때문에 4+ 1+ 1+ 1 = 7 이어야 하지만, 8이 나오는 모습을 볼 수 있었다.

 

그 이유는 

 

바이트 패딩: 

몇몇 컴파일러는 구조체의 필드를 메모리에 위치시킬때 중간에 빈공간없이 쭉 이어서 할당하는 경우도 있지만 대부분의 컴파일러는 성능향상을 위해 CPU가 접근하기 쉬운 위치에 필드를 배치하는데(OS나 컴파일러에 따라 4바이트단위 또는 8바이트 단위로 끊는작업을 함) 이를 "바이트 패딩"이라고 하며, 그러다보니 중간이 빈 공간이 들어가게 되는데 이 빈 공간을 "패딩비트"라 한다.  

 

이녀석 때문이다.

 

패딩 비트를 제거해주고, 연속된 메모리에 데이터를 할당하고 소켓통신을 해야만 올바르게 데이터를 주고 받을 수 있다.

 

그렇기 때문에 소켓통신시에 패킹이 필요한 것이다.

 

사용방법은 간단!!

 

이런식으로 데이터를 묶어주면 된다.

헤더는 #include <stdio.h>

 

pack(push, 1) // 1바이트 크기로 정렬하겠다는 의미

pack(pop) // 정렬 설정을 이전 상태(기본값)로 되돌리겠다는 의미

 

해당방법은

  • Visual Studio, GCC 4.0 이상

의 환경에서만 가능하다.

 

이전버전을 사용한다면( 그럴 일은 거의 없지만..) 혹은 다른 방법을 원한다면 아래 링크들을 참고

 

dojang.io/mod/page/view.php?id=432

 

C 언어 코딩 도장: 51.2 구조체 정렬 크기 조절하기

데이터 전송이나 저장을 할 때 구조체 정렬을 피하려면 어떻게 해야 할까요? 그런데 C 언어에서는 구조체를 정렬하는 표준 방법이 없습니다. 하지만 걱정하지 않아도 됩니다. 각 컴파일러에서

dojang.io

 

www.vbflash.net/164

https://3dmpengines.tistory.com/1571 [3DMP]

 

C/C++ 및 C# Scoket 통신

Introduction 본 블로그의 포스팅과 관련된 내용을 작성한지 몇년이 지났는데, 에버노트를 정리하다가 버릴까 하던 내용을 다시 다시 주워서 정리 후 포스팅합니다.  최근에는 C/C++을 이용한 개발

www.vbflash.net

 

반응형
반응형

우선순위 큐는 일반 큐와는 다르게  트리구조입니다.

그리고 현재 저장된 값들 중 최댓값 혹은 최솟값을 내놓습니다.

그렇기 떄문에 삽입, 삭제 할 때 시간복잡도는 O(logN) 입니다.

 

<사용 함수>
push(X) // 우선순위 큐에 새로운 값을 추가

top() // 우선순위 큐의 루트 노드 리턴

pop() // 우선순위 큐에서 루트 노드를 삭제

size() // 우선순위 큐 내에 포함된 원소들의 수를 리턴

empty() // 우선순위 큐가 empty이면 true를 리턴

 

우선순위 큐 중 최댓값을 내놓는 것을 Max 힙, 최솟값을 내놓는 것을 Min 힙이라고 부릅니다.

 

Max 힙을 사용

 

1. priority_queue< int, vector<int> > q;
2. priority_queue< int, vector<int>, less<int> > q; 

* less 의미가 Max 힙의 의미와 헷갈릴 수 있으니 주의

3. 전달할 데이터가 2개 이상이면 다음과 같이 pair로 묶는다.

priority_queue< pair<int,int> > pq;

 

Min 힙을 사용


1. priority_queue< int, vector<int>, greater<int> > q;

2. 혹은 priority_queue< int, vector<int> > q;를 쓰고 push(-X) & -top() 같이 사용 가능.

3. 전달할 데이터가 2개 이상이면 다음과 같이 pair로 묶는다.

priority_queue< pair<int,int> > pq;를 쓰고 push(-X) & -top() 같이 사용 가능.

 

pair로 묶었다면 .first 값을 1순위로 값을 뽑아내고 그다음 .second 값을 2순위

pair< int,pair<int,int> > 형태는 .first 1순위 .second.first 2순위 .second.second 3순위

 

그리고 sort함수와 동일하게 사용자가 직접 함수를 생성해서 우선순위를 구분해줄 수도 있습니다.

그건 다른 포스팅에서 올리도록 하겠습니다. 




반응형

+ Recent posts