Development note/Linux

[Linux] 멀티 세션 사용하기(screen)

v명월v 2021. 2. 16. 15:29

안녕하세요. 명월입니다.

 

이 글은 Linux에서 멀티 세션 사용하기(screen)에 대한 글입니다.

 

우리가 윈도우에서 리모트를 접속을 하면 세션이 생성되어서 세션을 종료하지 않고 끊는 것만으로 세션이 유지가 됩니다.

그러면 리눅스에서는 어떨까 Putty로 접속해서 echo 서버를 실행시켜 보겠습니다.

import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {
  private static char CR = (char) 0x0D;
  private static char LF = (char) 0x0A;

  public static void main(String... args) {
    // 싱글 쓰레드 풀
    Executors.newSingleThreadExecutor().execute(() -> {
      // Server 소켓 생성
      try (ServerSocket server = new ServerSocket()) {
        // 서버 대기 (Listen)할 포트 설정
        server.bind(new InetSocketAddress(10000));
        // 다중 접속을 위한 다중 쓰레드 풀 생성
        ExecutorService service = Executors.newCachedThreadPool();
        while (true) {
          // Client 접속
          final Socket client = server.accept();
          // 다중 쓰레드 풀에 client을 넣는다. 그리고 위 accept를 다시 대기해야지
          service.execute(() -> {
            // client로 메시지를 전송할 sender와 메시지를 받을 receiver를
            try (final OutputStream sender = client.getOutputStream();
                final InputStream receiver = client.getInputStream();) {
              // 메시지를 모으기 위한 버퍼
              StringBuffer sb = new StringBuffer();
              // 메시지 발송
              Runnable send = () -> {
                try {
                  // 버퍼로 부터 데이터를 가져와서 byte형식으로 변환.
                  byte[] data = sb.toString().getBytes();
                  // 메일 발송.
                  sender.write(data, 0, data.length);
                  sb.setLength(0);
                } catch (Throwable e) {
                  e.printStackTrace();
                }
              };
              sb.append("Welcome server!\r\n>");
              // welcome 메시지 발송
              send.run();
              while (true) {
                // 수신 대기 버퍼
                byte[] data = new byte[1024];
                // 메시지를 수신한다.
                receiver.read(data, 0, data.length);
                // 버퍼의 빈 값(\0)을 제거
                String buffer = new String(data).replace("\0", "");
                sb.append(buffer);
                // 메시지 끝이 개행일 경우
                if (sb.length() > 2 && sb.charAt(sb.length() - 2) == CR
                    && sb.charAt(sb.length() - 1) == LF) {
                  // 개행 제거
                  sb.setLength(sb.length() - 2);
                  // 버퍼를 string으로 변환
                  String msg = sb.toString();
                  // 콘솔에 표시
                  System.out.println(msg);
                  // exit경우 접속 정료
                  if ("exit".equals(msg)) {
                    break;
                  }
                  // echo 메시지 만들기
                  sb.insert(0, "Echo - ");
                  sb.append("\r\n>");
                  // 에코 메시지 송신
                  send.run();
                }
              }
            } catch (Throwable e) {
              e.printStackTrace();
            } finally {
              // 서버 종료
              try {
                client.close();
              } catch (Throwable e1) {
                e1.printStackTrace();
              }
            }
          });
        }
      } catch (Throwable e) {
        e.printStackTrace();
      }
    });
  }
}

링크 - [Java] NIO(Non-Blocking IO) Socket 통신

위 소스를 참고했습니다.

로컬에서 텔넷으로 Putty로 만든 세션에서 echo 서버를 기동하니 서로 통신이 되는 것을 확인할 수 있습니다.

이 상태에서 제가 putty를 종료시켜 보겠습니다.

접속이 끊겨 버리네요..

즉, 윈도우 환경처럼 putty를 종료시키면 세션만 끊기는 것이 아니라 아예 세션이 종료가 되어 버립니다.

일단 리눅스에서는 꼭 세션에서 프로그램을 기동할 필요없이 &를 이용하거나 service를 이용해서 백그라운드에서 사용하게 할 수 있습니다.

링크 - [CentOS] Linux에서 프로그램을 백그라운드에서 실행하는 방법과 서비스 등록 방법

 

그런데 백그라운드가 아닌 윈도우처럼 세션을 열어서 실행하고 싶을 때도 있습니다. 예를 들면, 서버 프로그램이 아닌 배치 프로그램을 실행하는데 시간이 오래 걸리는 작업이라든가..

그럴 때는 screen이라는 프로그램을 사용해서 멀티 세션을 생성할 수 있습니다. 세션을 여러개 열어서 동시에 여러 작업도 가능합니다.

 

먼저 yum을 이용해서 screen을 설치하겠습니다.

설치가 완료되었습니다.

여러가지 옵션이 있습니다만, screen에서 사용하는 옵션은 세션 열기, 닫기, 접속하기, 끊기, 그리고 screen list 확인하기가 전부입니다. 그 외에는 저도 사용해 본 적이 없습니다.

screen -S 세션명

-S는 세션명으로 세션을 만들어 접속합니다. 참고로 (대소문자 구분입니다. 대문자 S입니다.)

그냥 -S 세션명 없이 screen만으로도 기본 default 세션을 만들어 접속합니다.

저는 그냥 default로 접속합니다.

screen -list

다른 putty로 터미널을 열고 접속해서 screen 세션을 확인합니다.

11196.pts-0.localhost로 접속이 되었는데.. 앞의 11196은 세션 번호이고 그 뒤 점(.) 이후는 세션 이름입니다.

즉, pts-0.localhost의 이름으로 접속이 된 것입니다. 그 뒤의 괄호 안에 Attached의 표시는 다른 터미널에서 현재 screen에 접속 중이라는 표시집니다.

screen -D 세션명

이제 다른 터미널에서 -D 옵션으로 세션을 끊어 보겠습니다.

Detached로 바뀌었습니다. 그럼 screen 세션에 접속되어 있는 터미널은 튕겨져 나옵니다.

screen -R 세션명

이번에는 -R 옵션으로 다시 session으로 접속합니다.

다른 터미널에서 다시 screen 상태를 확인하면 Attached로 바뀌어 있습니다.

그리고 최종적으로 session에 들어가서 exit로 빠져나오면 screen 세션이 종료됩니다.

여기까지는 cmd에서 옵션을 통해서 screen을 제어하는 방법이었습니다.

 

이번에는 screen에 접속한 상태에서 제어하는 방법입니다.

먼저 screen을 실행한 상태에서 Ctrl+a, "를 누릅니다.(여기서 포인트가 "는 Shift를 눌러야 나오는 것이니깐 Ctrl+a를 누르고 Ctrl를 떼고 Shift를 누르는 상태에서 "를 누르면 됩니다.)

현재 스크린 상태가 나오는데.. 저는 현재 세션이 한 개있습니다.

엔터를 치고 들어와서 Ctrl+a,c를 눌러서 세션을 확장합니다. 그런 후에 다시 Ctrl+a, "를 누르면 Screen 세션이 두개 있는 것을 확인 할 수 있습니다.

다시 0번 세션으로 돌아와서 이번에는 Ctrl+a, |를 눌러 보겠습니다.

화면이 분할되어 있는 것을 볼 수 있네요.

이 분할된 화면을 전환하는 것은 Ctrl+a, Tab키를 누르면 전환이 가능합니다.

 

이번에는 다른 세션으로 이동하는 것입니다.

기본적으로 Ctrl+a, "로 눌러서 선택해도 되는데 빠르게 이동하는 방법은 Ctrl+a,p(이전 세션) 또는 Ctrl+a,n(다음 세션) 그리고 Ctrl+a,a는 바로 전에 접속한 세션으로 이동이 가능합니다.

여기서 최종적으로 세션과 쉘을 종료하는 것은 exit를 눌러서 빠져나오면 됩니다.

 

다시 옵션과 명령어를 정리해 보겠습니다.

옵션 및 명령어 설명
옵션
screen -S 세션명 screen 세션 생성
screen -D 세션명 screen 세션 접속 끊기
screen -R 세션명 screen 세션 재 접속
screen -list screen 세션 리스트 확인
명령어
Ctrl-a, c 세션 안에서의 새로운 쉘 생성
Ctrl-a, n 세션 안에서의 다른 쉘로 이동
Ctrl-a, p 세션 안에서의 이전 쉘로 이동
Ctrl-a, d 세션 연결 끊기(세션 종료를 뜻하는 것 아니다.)
Ctrl-a, " 쉘 리스트를 보여주고 이동 커서가 나온다. 커서로 선택할 경우 이동도 가능한다.
Ctrl+a, | 화면 분할
Ctrl+a, tab 화면 분할 시에 화면 전환
Ctrl+a, Q 화면 분할 종료

최근 Linux 환경은 아주 먼 옛날처럼 console로 접속하는 경우가 없습니다. 혹시라도 데스트탑으로 사용한다고 해도 이제는 GUI 환경이 있고, console 명령을 사용한다고 해도 거의 MAC이나 Window환경에서 원격화면이기 때문에 솔직히 Screen의 화면 분할 기능이나 쉘을 여러가 나누어서 사용하는 건 없다고 생각됩니다.

이제 screen으로 사용하는 건 새로운 세션을 열어서 백그라운드에서 배치를 실행하는 것 뿐일까?

 

마지막으로 처음에 사용되었던 echoserver가 putty를 종료하고도 실행이 되는 것을 확인해 보겠습니다.

Linux에서 screen으로 실행하고 putty 화면의 세션을 종료했습니다. 그래도 socket 접속이 되는 것이 확인이 되네요.

 

여기까지 Linux에서 멀티 세션 사용하기(screen)에 대한 글이었습니다.

 

궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.