728x90

예제 코드 설명

  • 하나의 스레드는 전역 변수 target을 계속 더해주고(target++), 다른 하나의 스레드는 target을 계속 빼주는(target--) 멀티 스레드 예제 코드입니다.
  • 스레드 동기화(Thread Synchronization)없이 두 개의 스레드가 경쟁하는 구조입니다.

Windows

  • OS : Windows 10
#include <windows.h> // WinAPI 사용 
#include <stdio.h>

int target = 0;

int WINAPI addTarget(LPVOID param) { // 파라미터로 원래 LPVOID 타입을 사용하지만 void * 를 사용해도 같음 
	int limit = *(int *) param;
	int i=0;
	for (i=1; i<=limit; i++) {
		printf("[ADD] target : %d\n", ++target);
	}
	return 0;
}

int WINAPI subtractTarget(LPVOID param) {
	int limit = *(int *) param;
	int i=0;
	for (i=1; i<=limit; i++) {
		printf("[SUBTRACT] target : %d\n", --target);
	}
	return 0;
}

int main() {
	int threadId1;
	int threadId2;
	HANDLE threadHandle1;
	HANDLE threadHandle2;
	int param=100;
	
	// 스레드 생성
	threadHandle1 = CreateThread(NULL, 0, addTarget, &param, 0, &threadId1);
	threadHandle2 = CreateThread(NULL, 0, subtractTarget, &param, 0, &threadId2);
	
	Sleep(3000);
	printf("target : %d\n", target);
    return 0;
}


동기화를 안 했기 때문에 두 개의 스레드가 각자 돌아가면서 값을 출력한다.

Linux

  • OS : Ubuntu 16.04 LTS
  • GCC : 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.12)
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int target = 0;

void * addTarget(void * param)
{
  int limit = *(int *) param;
  int i=0;
  for (i=1; i<=limit; i++) {
    printf("[ADD] target : %d\n", ++target);
  }
}

void * subtractTarget(void * param)
{
  int limit = *(int *) param;
  int i=0;
  for (i=1; i<=limit; i++) {
    printf("[SUBTRACT] target : %d\n", --target);
  }
}
 
int main()
{
  pthread_t add, sub;
  int param = 100;
  
  int add_id = pthread_create(&add, NULL, addTarget, &param);
  // error handling, 정상적으로 생성되면 0 반환
  if (add_id < 0)
  {
      perror("thread create error : ");
      exit(0);
  }
  
  int sub_id = pthread_create(&sub, NULL, subtractTarget, &param);
  if (sub_id < 0)
  {
      perror("thread create error : ");
      exit(0);
  }
 
  sleep(3000);
  printf("target : %d\n", target);
 
  return 0;
}

  • gcc 컴파일 시 -lpthread 옵션 추가
728x90

'운영체제' 카테고리의 다른 글

[운영체제] 프로세스와 스레드  (1) 2024.09.18
728x90

들어가기 앞서

본 문서는 Windows에서 특정 포트가 실행 상태를 확인하고, 해당 포트에서 실행되고 있는 프로세스를 종료하는 방법을 정리합니다.

 

관련 문서

TL;DR

# 현재 실행되는 프로세스 및 PID를 확인합니다
$ netstat -ano

# 특정 포트(e.g. 8080)만 확인하고 싶은 경우 find 명령어를 함께 사용한다
$ netstat -ano | find "8080"

# 해당 프로세스의 아이디(PID)를 이용하여 프로세스를 종료합니다
$ taskkill /f /pid 22644

 

배경

3000번 포트가 현재 사용 중이다

 

개발 도중 사용하고 있던 특정 포트가 종료되지 않아 다시 명령어를 입력했을 때 에러가 발생하는 경우를 한 번씩 겪는다.
(ex. node:3000, django:8080, tomcat:8080)

이번 기회에 윈도우에서 명령 프롬프트(CMD)를 통해 특정 포트가 열려있는지 검색하고 해당 포트를 죽이는 명령어에 대해서 정리하고자 한다.

 

특정 포트 검색 (netstat -ano)

  • 기본 명령어는 netstat 이다.
    netstat 명령어를 통해 포트 별 상태를 확인한다
  • 그런데 이렇게 해서는 우리가 원하는 특정 포트가 현재 사용되고 있는지와 taskkill(특정 포트 종료 명령어)을 사용하기 위해서 알아야 할 pid가 나오지 정확히 나오지 않기 때문에 netstat 명령어에 옵션을 붙여준다.
  • 다양한 옵션에 대한 설명은 netstat help를 통해 알 수 있다.
    netstap help
  • 우리는 netstat -ano를 실행한다.
    - -a : 모든 연결 포트 표시
    - -n : 주소와 포트 번호를 숫자 형식으로 표시
    - -o : 프로세스 ID (PID) 표시
    - 로컬에서 개발 중이었다면 굳이 n 옵션은 사용하지 않아도 포트는 확인할 수 있다.
    netstat -ano
  • 우리가 현재 우리가 찾을려는 포트는 3000번 포트이다.
  • 3000번 포트를 사용하고 있는 프로세스의 PID는 22644임을 확인할 수 있다.

 

특정 포트 종료 (taskkill /f /pid [PID])

  • PID를 확인했다면 taskkill 명령어를 통해 종료시킬 수 있다.
  • taskkill 명령어 또한 다양한 옵션을 가지고 있다. 다양한 옵션에 대해 알고 싶다면 taskkill /?를 통해 확인해보자
    taskkill
  • 우리는 taskkill /f /pid [PID]를 통해 특정 포트를 종료하도록 한다.
    - /f : 강제 종료
    - /pid [PID] : 종료할 프로세스의 PID 지정
  • 우리는 pid가 22644인 프로세스를 종료하고자 했기 때문에 taskkill /f /pid 22644를 통해 3000번을 사용하고 있는 프로세스를 종료한다.
  • 다시 netstat -ano를 통해 현재 연결 포트를 확인해보자
  • 3000번 포트가 말끔히 종료되었다.
  • 다시 node를 실행해보면 잘 실행된다.

추가 (find)

  • 우리는 특정 포트를 확인할 때 netstat -ano를 통해 포트를 확인했다.
  • 사실 이건 비효율적인 명령이다.
  • find 명령어와 함께 사용하면 손쉽게 특정 포트를 확인할 수 있다.
  • netstat -ano | find "3306"과 같이 명령어를 실행하면 다음과 같이 netstat -ano의 출력 결과 중 "3306"이 포함된 부분만 출력된다.
728x90
728x90

0. Intro

최근 구상하고 있는 아두이노 프로젝트와 관련하여 아두이노와 모바일 디바이스를 통한 인식을 위해서 여러 가지 방법을 생각하다가 현재 코로나 때문에 우리 학교에서 학교를 출입할 때 사용하는 방식이 생각났다. 학교 애플리케이션에 접속하면 QR코드를 발급해주고 건물 입구에서 해당 QR코드를 통해 사용자를 인식하는 방법이다. 이 방법을 적용해보기 위해 QR코드 관련 사이트와 포스트를 찾아보다 재밌는 사이트를 발견했다.

https://www.the-qrcode-generator.com/

사용자가 입력하는 텍스트, URL, 전화번호 등을 QR코드로 생성해주는 사이트이데 QR코드 생성과 인식을 모두 지원하고 있다.

그래서 프로젝트에 적용해보기 전에 재미로 QR코드를 직접 만들고 인식할 수 있는 웹 사이트를 간단하게 만들어보기로 했다.

1. 프로젝트 준비

1) 프로젝트 구조

| --------- models
|              |-------- user.js
|
|---------- views
|              |-------- home.ejs
|
|---------- app.js

2) node 프로젝트 생성한다.

  • 터미널을 열어서 원하는 위치에 폴더를 생성
    mkdir qrcode // qrcode 디렉토리 생성
    cd qrcode // qrcode 디렉토리로 이동
    npm init -y

3) 필요한 패키지 설치한다.

npm i express body-parser ejs mongoose qrcode nodemon

4) 설치가 성공적이라면 package.json을 확인하면 아래 사진과 같이 dependencies에 우리가 설치한 6가지 항목이 설치된 것을 확인할 수 있다.

2. Model

  • 사용자가 이름과 전화번호를 입력하면 해당 정보에 대한 QR코드를 생성해주고 해당 내용을 DB에 저장한다.
  • 본 서비스는 간단하게 몽고 DB를 이용한다.
  • models 폴더를 만들고 해당 폴더 내에 user.js를 생성
  • 아래 코드를 작성
var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({    
      name:{    
          type:String    
      },    
      tel:{    
          type:String    
      }    
});
module.exports = mongoose.model('user',userSchema);

3. View

  • views 폴더를 만들고 폴더 내에 home.ejs를 작성한다.
<html lang="en">    
<head>    
    <meta charset="UTF-8">    
    <meta name="viewport" content="width=device-width, initial-scale=1.0">    
    <meta http-equiv="X-UA-Compatible" content="ie=edge">    
    <title>QR 코드 생성기</title>    
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">    
</head>    
<body>    
    <div class="nav justify-content-center">    
        <div class="card border-primary mb-3" style="max-width: 18rem;margin-top: 20px;">    
            <div class="card-header">유저 정보</div>    
            <div class="card-body text-primary">    
                <form action="/" method="post">    
                    <input type="text" name="name" placeholder="이름을 입력해주세요" class="form-control"><br>    
                    <input type="text" name="phno" placeholder="전화번호를 입력해주세요" class="form-control"><br>    
                    <div class="text-center"> <input type="submit" value="QR 코드 만들기" class="btn"> </div>     
                </form>    
            </div>
            <div class="text-center">
                <button class='btn' onclick="location.href='/';">생성</button>
                <button class='btn' onclick="location.href='/identify';">인식</button>
            </div>  
        </div>
    </div>   
    <% if (data) {%>     
        <div class="text-center">    
            <h5>QR Code</h5>    
            <img src="<%=data%>" alt="" style="width:100px; height:100px;">    
        </div>    
    <% } %>      
</body>    
</html>
 

4. app.js

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const qrCode = require('qrcode');
const userModel = require('./models/user');

const URL = "mongodb://localhost:27017/qrcode";
mongoose.connect(
    URL,
    {
        useNewUrlParser: true,
        useFindAndModify: false,
        useUnifiedTopology: true
    },
    () => {
        console.log("Connected to DB");
    }
);

const app = express();
app.set("view engine", "ejs");
app.use(express.static('./static'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.get('/', (req, res) => {
    userModel.find((err,data)=>{    
        if (err) {    
            console.log(err);    
        } else {    
            if (data != ''){
                var latest =  data[data.length-1].name + " / " + data[data.length-1].tel;

                qrCode.toDataURL(latest, {
                    errorCorrectionLevel:'H'
                }, (err, url) => {
                    res.render('home', { data:url })    
                });
            }else{    
                res.render('home', { data:'' });    
            }    
        }    
     });    
});

app.post('/', (req,res) => {    
    var user = new userModel({    
        name: req.body.name,    
        tel: req.body.tel    
    });
    
    user.save((err,data) => {    
        if (err) {    
            console.log(err);    
        } else {    
            res.redirect('/');    
        }    
    });    
});

app.listen(3000);

실행 화면

  • 터미널에서 npm start 후 시작 화면
  • 유저 정보 입력
  • QR 코드 만들기 버튼 클릭
  • QR 코드 인식 영상

후속

  • 본 편은 원하는 텍스트를 입력하여 QR코드로 생성했다. 현재는 텍스트지만 유저의 PK 또는 ObjectID를 넘겨준다면 QR코드를 통해 유저를 인증할 수 있을 것 같다.
  • 후속편은 QR 코드를 인식하고 해당 값에 따라서 유저 정보를 출력하는 기능을 작성 할 예정.

Github Source Code

참고 사이트 :
https://www.npmjs.com/package/qrcode
https://www.c-sharpcorner.com/blogs/generate-qrcode-in-node

728x90
728x90

Signaling 예제 코드

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

// 핸들러 함수 정의
void handlerFunc(int sig) {
  printf("handlerFunc() 호출됨\n");
  // SIGINT : 터미널 인터럽트
  // SIG_DFL : 기본 행동 수행, 메인 함수가 하던 일을 계속 수행하고 한 번 더 SIGINT가 오는 경우 프로세스 종료
  signal(SIGINT, SIG_DFL);
}

int main() {
  // SIGINT(키보드 인터럽트) 신호를 받으면 handlerFunc 수행
  signal(SIGINT, handlerFunc);

  int count = 0;
  while(1) {
    printf("count : %d\n", count++);
    sleep(1);
  }
  exit(0);
}

실행 결과

시그널 타입

  • SIGINT : 키보드 인터럽트
  • SIGFPE : 부동 소수점 예외
  • SIGKILL : 프로세스 종료
  • SIGCHLD : 자식 프로세스가 정지 또는 종료
  • SIGSEGV : 세그먼트 오류(비정상 종료, 메모리 엑세스 오류)
728x90

'운영체제 > IPC' 카테고리의 다른 글

[OS] IPC - Message Passing  (0) 2022.12.26
[OS] IPC - Shared Memory  (0) 2022.12.26
728x90

프로세스, 스레드, IPC에 관한 내용은 이 글을 참고하자

Message Passing 예제

sender.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define BUFFER_SIZE 1024

// 메세지 형태 정의
typedef struct {
  long msgtype;
  int value;
  char buf[BUFFER_SIZE];
} msgbuf;

int main() {
  int key_id;
  msgbuf mybuf;
  int count = 0;
 
  // 메세지 생성
  key_id = msgget((key_t) 1234, IPC_CREAT|0666);
  if (key_id == -1) {
    perror("msgget() error");
    exit(0);
  }
  
  // 메세지 타입 설정
  mybuf.msgtype = 1;
  while (1) {
    // value 값 1 증가시켜서 메세지 전송
    mybuf.value = count++;
    printf("value : %d\n", mybuf.value);
    
    if (msgsnd(key_id, &mybuf, sizeof(msgbuf), IPC_NOWAIT) == -1) {
      perror("msgsnd() error");
      exit(0);
    }
    
    sleep(10);
  }
}

receiver.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define BUFFER_SIZE 1024

// 메세지 형태 정의
typedef struct {
  long msgtype;
  int value;
  char buf[BUFFER_SIZE];
} msgbuf;

int main() {
  int key_id;
  msgbuf mybuf;
  long msgtype = 1; // 수신받을 메세지 타입 미리 설정
 
  // 메세지 생성
  key_id = msgget((key_t) 1234, IPC_CREAT|0666);
  if (key_id == -1) {
    perror("msgget() error");
    exit(0);
  }
  
  while (1) {
    // 메세지 타입이 1 일 때 수신
    if (msgrcv(key_id, &mybuf, sizeof(msgbuf), 1, 0) == -1) {
      perror("msgrcv() error");
      exit(0);
    }
    
    // 수신 받은 메세지에서 value 출력
    printf("value : %d\n", mybuf.value);
  }
}

실행화면

헤더 파일 및 주요 함수

헤더 파일

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg)

  • 메세지를 생성

int msgsnd(int msqid, struct msgbuf * msgp, size_t msgsize, int msgflg)

  • 메세지 전송

ssize_t msgrcv(int msgid, struct msgbuf * msgp, size_t msgsize, long msgtype, int msgflg)

  • 메세지 수신
728x90

'운영체제 > IPC' 카테고리의 다른 글

[OS] Signaling  (0) 2022.12.26
[OS] IPC - Shared Memory  (0) 2022.12.26
728x90

Process

  • 컴퓨터에서 실행되고 있는 프로그램
  • 실행되고 있는 프로그램의 인스턴스
  • 프로세스간 독립적
  • CPU로부터 메모리 할당

Thread

  • 프로세스 내에서 실행되는 흐름의 단위
  • 프로세스가 할당받은 자원을 이용
  • 같은 메모리 공간 공유

IPC

  • 프로세스는 독립적으로 실행되기 때문에 메모리를 공유할 수 없다.
  • 따라서 프로세스간 통신을 통해 서로 데이터를 주고 받을 수 있게 해야한다.
  • 방법은 다음과 같다.

1) Message Passing

  • 커널을 통해 메시지를 전달
  • 안전하지만 성능이 떨어짐 (Overhead가 큼)
  • 예제

2) Shared Memory

  • 프로세스간 공유된 메모리를 생성 후 이용
  • 성능이 좋지만 동기화 문제 발생 가능
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
  int shmid;
  int pid;
  
  int * cal_num;
  void * shared_memory = (void *) 0;
  
  // 공유 메모리 공간 생성
  shmid = shmget((key_t) 1234, sizeof(int), 0666|IPC_CREAT);
  
  // shmget() 실패 시 -1 return
  if (shmid == -1) {
    perror("shmget failed : "); // 오류 메시지 출력
    exit(0);
  }
  
  printf("shmid return value : %d\n", shmid);
  
  // 공유 메모리를 사용하기 위해 프로세스 메모리 부착
  shared_memory = shmat(shmid, (void *)0, 0);
  if (shared_memory == (void *) -1) {
    perror("shmat failed : ");
    exit(0);
  }
  
  cal_num = (int *) shared_memory;
  // 자식 프로셋스 생성
  pid = fork();
  
  if (pid == 0) {
    // 자식 프로세스
    shmid = shmget((key_t) 1234, sizeof(int), 0);
    
    if (shmid == -1) {
      perror("shmget failed : "); // 오류 메시지 출력
      exit(0);
    }
    shared_memory = shmat(shmid, (void *) 0,  0666|IPC_CREAT);
    if (shared_memory == (void *)-1) {
      perror("shmat failed : ");
      exit(0);
    }
    cal_num = (int *) shared_memory;
    *cal_num = 1;
    
    while(1) {
      *cal_num = *cal_num + 1;
      printf("child %d\n", *cal_num);
      sleep(1);
    }
  } else if (pid>0) {
    // 부모 프로세스
    while(1) {
      sleep(1);
      printf("*cal_num : %d\n", *cal_num);
    }
  }
}

int shmget(key_t , key, size_t size, int flags)

- #include  에 포함
- 새 공유 메모리 세그먼트를 생성하거나 키를 찾는데 사용
- 0666 | IPC_CREAT
0666 : Linux에서 일반적인 엑세스 권한, 메모리 세그먼트 권한 지시
IPC_CREAT : 공유 메모리에 대한 새 메모리 세그먼트를 만들도록 지시
- 참고 : [What is the use of IPC_CREAT | 0666 Flag in shmget()?](https://stackoverflow.com/questions/40380327/what-is-the-use-of-ipc-creat-0666-flag-in-shmget-function-in-c) - Stackoverflow

void shmat(int id, const void addr, int flags)

- #include <sys/shm.h> 에 포함
- 공유 메모리 세그먼트를 프로세스에 연결하는데 사용 ⇒ 메모리 내용에 엑세스 가능

fork()

- 자식 프로세스 생성

 

 
728x90

'운영체제 > IPC' 카테고리의 다른 글

[OS] Signaling  (0) 2022.12.26
[OS] IPC - Message Passing  (0) 2022.12.26
728x90

IP 주소

  • 네트워크 상에서 유일하게 식별될 수 있는 컴퓨터 주소
  • 192.142.11.15 같이 숫자로 된 주소는 기억하기 어렵기 때문에 www.google.com과 같이 문자로 구성된 도메인 이름으로 바꿔서 사용 -> DNS(Domain Name System)
  • 윈도우의 경우 명령 프롬프트를 열어 ipconfig 명령을 통해 자신의 IP 주소를 확인할 수 있음

포트 (Port)

  • 통신하는 프로그램 간에 가상의 연결단
    - IP 주소를 통해 네트워크 상의 컴퓨터 또는 시스템을 식별하고
    - 포트 번호를 통해 통신할 응용 프로그램을 식별
  • 포트 번호 : MAC adress(호스트의 NIC 판별)와 IP adress(호스트 판별)를 통해
    상대 컴퓨터까지 데이터가 도달한 후, 데이터를 받을 프로세스를 식별하기 위해 포트번호 사용

URL (Uniform Resource Locater)

  • 인터넷 상의 자원에 대한 주소
  • 구조

 

 

728x90

'네트워크' 카테고리의 다른 글

TCP, UDP  (0) 2022.12.26
OSI 7계층  (0) 2022.12.26
728x90

본 글을 읽기 전에 OSI 7계층에 대해 먼저 알아보도록 하자

TCP(Transmission Control Protocol)

  • 송/수신 호스트 내 프로세스 상호 간에 신뢰적인 연결지향성 서비스를 제공
  • IP의 비신뢰적인 최선형 서비스에다가 신뢰적인 연결지향성 서비스를 제공하게 됨
  • 신뢰적인 전송을 보장함으로써, 어플리케이션 구현이 한층 쉬워지게 됨
  • 신뢰성 있음 (Reliable)
  • 패킷 손실, 중복, 순서바뀜 등이 없도록 보장
  • TCP 하위계층인 IP 계층의 신뢰성 없는 서비스에 대해 다방면으로 신뢰성을 제공
  • 연결지향적 (Connection-oriented)
  • 같은 전송계층의 UDP가 비연결성(connectionless)인 것과는 달리, TCP는 연결지향적임
  • 이 경우, 느슨한 연결(Loosly Connected)을 갖으므로 강한 연결을 의미하는 가상회선이라는 표현 보다는 오히려 연결지향적이라고 말함
  • 연결 관리를 위한 연결설정 및 연결해제 필요
  • 양단간 어플리케이션/프로세스는 TCP가 제공하는 연결성 회선을 통하여 서로 통신

UDP

  • 전송 계층의 통신 프로토콜의 하나 (TCP에 대비됨)
  • 신뢰성이 낮은 프로토콜로써 완전성을 보증하지 않으나,
  • 가상회선을 굳이 확립할 필요가 없고 유연하며 효율적 응용의 데이타 전송에 사용
  • 비연결성이고, 신뢰성이 없으며, 순서화되지 않은 Datagram 서비스 제공
  • 메세지가 제대로 도착했는지 확인하지 않음 (확인응답 없음)
  • 수신된 메세지의 순서를 맞추지 않음 (순서제어 없음)
  • 흐름 제어를 위한 피드백을 제공하지 않음 (흐름제어 없음)
  • 검사합을 제외한 특별한 오류 검출 및 제어 없음 (오류제어 거의 없음)
    UDP를 사용하는 프로그램 쪽에서 오류제어 기능을 스스로 갖추어야 함
  • 데이터그램 지향의 전송계층용 프로토콜 (논리적인 가상회선 연결이 필요없음)
    비연결접속상태 하에서 통신
  • 실시간 응용 및 멀티캐스팅 가능
  • 빠른 요청과 응답이 필요한 실시간 응용에 적합
  • 여러 다수 지점에 전송 가능 (1:多)
  • 헤더가 단순함
  • UDP는 TCP 처럼 16 비트의 포트 번호를 사용하나,
  • 헤더는 고정크기의 8 바이트(TCP는 20 바이트) 만 사용
    즉, 헤더 처리에 많은 시간과 노력을 요하지 않음

TCP vs UDP

  • 가장 큰 차이는 신뢰성과 연결성에 있음
  • TCP는 신뢰성 있고 연결지향적이지만 UDP는 신뢰성이 없고, 비연결적
  • TCP는 송신자-수신자 연결이 되어야 통신가능, UDP는 연결 없이도 통신 가능

TCP UDP 사용 예

  • TCP는 순서를 보장한다는 점과 신뢰도가 있다는 점에서 대부분의 HTTP 통신, 이메일이나 파일전송처럼 순서대로 도착해야 하는 상황에서 사용된다.
  • UDP는 순서는 보장해주지 못하지만 실시간으로 반응해야하는 실시간 동영상 플레이어나 게임, 혹은 DNS에서 사용. DNS의 경우 누군가 도메인을 쳤을때마다 그때 그때 서버와 클라이언트가 커넥션을 맺으면 속도가 느려지기 때문에 UDPf를 사용한다.

cf. 채팅에서 TCP를 사용하는 이유?
채팅에서 TCP를 사용하는 이유는 연결된 상태에서 순서대로 송신자와 수신자가 보낸 메세지를 그대로 전송할 수 있기 때문이다. 고로 양뱡향통신에 유리하다. (UDP는 그 순서를 보장해주지 못하기 때문이다.)

728x90

'네트워크' 카테고리의 다른 글

IP Address, Port, URL  (0) 2022.12.26
OSI 7계층  (0) 2022.12.26
728x90

OSI 7계층

  • 네트워크에서 통신이 일어나는 과정을 7단계로 나눈 것

목적

  • 흐름을 한 눈에 알아보기 쉽고, 문제 발생 시
    다른 층을 건들지 않고 문제가 발생한 곳만 고칠 수 있음.
  • 표준화를 통해 포트/프로토콜 문제 해결 -> 비용 절감
  • 계층별 기능과 통신 과정 정립을 통한 교육 목적

물리층(Physical Layer)

  • 전기적,기계적 특성을 이용해 통신 케이블로 데이터 전송
  • 데이터를 전기적인 신호로 변환 (비트 단위로 전송) (=전기적으로 On,Off)
  • 주요 장비 : 허브, 리피터, 케이블
    -> 케이블, 리피터, 허브를 통해 데이터를 전송
  • 물리적인 전송(물리적으로 직접 연결된 노드간의 전송)을 담당
  • 장치간 신뢰성 있는 정보를 전송 -> 에러 검출, 흐름 제어, 재전송
    ex. 데이터 전송 시 에러가 발생하면 DataLink층에서 검출하고, Transport층에서 에러를 수정
  • 전송되는 단위 : Frame
  • 주요 장비: 브리지, 스위치 (MAC address를 이용해서 통신)
  • 주요 프로토콜 : Ethernet(CSMA/CD), Token Ring, PPP, HDLC, ATM, LLC

-> 브릿지나 스위치를 통해 맥주소를 가지고 물리층에서 받은 정보를 전달
프레임에 주소 부여(MAC - 물리적 주소), 에러 검출, 흐름 제어, 재전송

네트워크층 (Network Layer)

  • 데이터를 목적지까지 가장 빠르게 전달하는데 목적 (라우팅)
  • 경로를 선택, 주소를 정하고, 경로에 따라 패킷을 전달 (IP를 주소 부여)
  • 데이터를 연결하는 다른 네트워크를 통해 전달함으로써 인터넷이 가능하게 만드는 계층
  • 전송되는 단위 : Packet
  • 주요 장비 : 라우터, L3 스위치(라우팅 기능이 장착된 스위치)
  • 주요 프로토콜 : IP, X.25

-> 패킷을 목적지까지 가장 빠르게 전달하는 것에 중점
에러는 상위계층에서 해결해 주기 때문에 신경X
IP 프로토콜 (신뢰성, 흐름제어 기능X) -> TCP 같은 상위 Transport층에 의존 (신뢰성 확보 위해)

전송층 (Transport Layer)

  • 양 끝단(End to End)의 사용자들이 신뢰성있고 정확한 데이터 전송을 담당
  • 보낼 데이터의 용량과 속도, 목적지 등을 처리하고, 통신을 활성화
  • 데이터가 잘 전송되고 있는지 확인하고, 에러가 발생하면 에러난 부분을 재전송 (TCP)
  • 시퀀스 넘버 기반의 오류 제어 방식 (세그먼트 관련)
  • 오류검출 및 복구, 흐름제어, 중복검사 수행
  • 전송되는 단위 : Segment
  • 주요 프로토콜 : TCP, UDP

세션층 (Session Layer)

  • 데이터가 통신하기 위한 논리적인 연결 (=포트 연결?)
  • 통신 세션을 구성하는 계층 (세션 설정, 유지, 종료, 전송 중단 시 복구 등)
  • 통신 장치간 상호작용 설정, 동기화, 통신을 관리하기 위한 방법 제공

표현층 (Presentation Layer)

  • 데이터의 형식을 정의
  • 서로 다른 환경의 컴퓨터, 프로그램들이 데이터를 서로 이해(번역)할 수 있도록 제공
  • 데이터의 인코딩, 디코딩, 암호화, 압축, 코드변환 수행

응용층 (Application Layer)

  • 사용자가 직접 눈으로 보고 실제로 작업하는 계층
  • 응용 프로서세와 관계하여 응용 서비스 수행 (ex. Telnet, SSH, SMTP, FTP, etc..)
  • 주요 프로토콜 : HTTP, FTP, SMTP

참고 사이트

728x90

'네트워크' 카테고리의 다른 글

IP Address, Port, URL  (0) 2022.12.26
TCP, UDP  (0) 2022.12.26
728x90

TCP/IP 프로토콜

  • TCP : Transmission Control Protocol
    - 두 시스템 간에 신뢰성 있는 데이터의 전송을 관장하는 프로토콜
  • IP : Internet Protocol
    - 패킷 교환 네트워크에서 호스트간 데이터를 주고 받는 것을 관장하는 프로토콜

cf. OSI 7계층 관련 글
cf. TCP vs UDP 관련 글
cf. IP주소, 포트 번호, URL 관련 글

자바의 URL 클래스

  • java.net 패키지에 포함

URL 객체 생성 방법

  1. 절대 경로로 URL 객체 생성
URL myGithub = new URL("https://github.com/ruthetum");
  1. 상대 경로로 URL 객체 생성
URL repo = new URL(myGithub, "speech-to-text-icampus");
// repo 객체가 담은 URL은 https://github.com/ruthetum/speech-to-text-icampus
  • 잘못된 주소의 URL을 입력할 경우 MalformedURLException 예외 발생

예제 : URL 주소에서 데이터(html) 읽기

public static void main(String[] args) {
        URL myGithub = null;
        try {
            myGithub = new URL("https://github.com/ruthetum");
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(myGithub.openStream()));

            String html;
            while ((html = bufferedReader.readLine()) != null) {  // 한 줄씩 읽기
                System.out.println(html);
            }
            bufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

URLConnection 클래스

  • 주어진 원격지의 주소 URL에 네트워크 접속 후 데이터를 보내거나 받을 수 있도록 하는 기능
  • 단순히 url에 접속하는 것도 가능하지만 파라미터를 설정해서 값을 넣어줄 수도 있음
  • 자바로 크롤링을 할 경우 Jsoup 패키지를 참고하자
URL url = new URL("https://github.com/ruthetum");
URLConnection conn = url.openConnection();

서버에 데이터를 보내기 위한 단계

  • 자바 프로그램이 웹 서버에 데이터를 보내기 위해 필요한 단계
  1. URL 생성
  2. URL 객체에서 URLConnection 객체를 얻어옴
  3. setDoOutput() 메소드로 doOutput 필드를 true로 설정
  4. connect() 메소드로 연결 설정
  5. 연결에서 출력 스트림을 얻음
  6. 출력 스트림에서 데이터를 출력
  7. 출력 스트림을 close() 메소드로 닫음

소켓 프로그래밍

Socket(소켓)

  • 네트워크 상에서 수행되는 두 프로그램 간의 양방향 통신 링크의 끝 단을 의미
  • 소켓은 특정 포트 번호와 연결되어 있음
  • 자바에서 데이터 통신 시 소켓 사용
  • 서버 소켓, 클라이언트 소켓으로 구성

ServerSocket 클래스

  • 서버 소켓에 사용되는 클래스
  • java.net 패키지에 포함
  • 주요 생성자
  • 주요 메소드
  • 예제 코드
// 서버 소켓 생성
ServerSocket server = new ServerSocket(5000);
// 클라이언트 접속 대기
Socket socket = server.accept();
// 네트워크 입출력 스트림 생성
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter((new OutputStreamWriter(socket.getOutputStream()));
// 클라이언트로부터 데이터 수신
String line = in.readline(); // 한 행 수신
// 클라이언트에게 데이터 전송
out.write("Hello, Client\n");
out.flush();
// 네트워크 접속 종료
socket.close();
// 서버 종료
server.close();
  • flush를 호출하면 스트림 속에 데이터를 남기지 않고 모두 전송

Socket 클래스

  • 클라이언트 소켓에 사용되는 클래스
  • java.net 패키지에 포함
  • 주요 생성자
  • 주요 메소드
  • 예제 코드
// 클라이언트 소켓 생성
Socket client = new Socket("128.12.1.1", 5000);
// 네트워크 입출력 스트림 생성
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
BufferedWriter out = new BufferedWriter((new OutputStreamWriter(client.getOutputStream()));
// 서버로 데이터 전송
out.write("hello\n");
out.flush;
// 접속 종료
client.close();

예제 : 채팅 프로그램 만들기

이미지 출처 : 명품 JAVA 프로그래밍 (황기태, 김효수 저)

728x90

'Java > Java 기본' 카테고리의 다른 글

[JAVA] 입출력 스트림과 파일 입출력  (0) 2022.12.26
[JAVA] 제네릭과 컬렉션  (0) 2022.12.26
[JAVA] 상속  (0) 2022.12.26

+ Recent posts