728x90

게임 서버를 구현하려면 무엇이 필요한가?

서버/클라이언트 모델의 온라인 게임을 만들기 위해 게임서버 빌드를 만들고 호스팅해야 함

서버빌드 ->(서버 엔진파트 , 게임 컨텐츠 파트)

서버 엔진파트 -> Transport 설계, 소켓통신 , API등 전반적인 네트워킹과 관련된 것들을 구현

게임 컨텐츠 파트 -> 게임의 온라인 컨텐츠 기능을 구현하는 부분

 

서버 엔진파트를 구현하는 방법에는 크게 두가지가 존재

1. 자체적으로 성능과 필요한 기능 등을 고려해 서버 엔진을 팀에서 자체적으로 제작 하는 방법

장점으로는 서버기능의확장, 유지보수 용이, 구현하고자 하는 게임에 최적화도 가능, 구현방식을 자유롭게 선택할수있음

단점으로는 필요한 네트워크지식과 제작에 드는시간과 비용이 만만치않음

.

2. 이미 만들어진 게임서버 라이브러리와 제공되는 API를 이용하는 방법. 장ㅈ엄으로는 서버 엔진을 구현하는 시간과 비용을 절약, 네트워크 프로그래밍에 관한 지식이 없어도 API사용 방법만 익히면  멀티플레이를 구현할수 있다. 단점으로는 

라이브러리 내에 구현된 서버 엔진에 따라서 원하는 기능의 추가나 성능 최적화가 제한 될 수 있다.

 

 


Mirror & Mirage 네트워크 라이브러리



Unet으로부터 포크(fork)해 다수의 개발자들이 오픈소스로 참여하고 제작한 Mirror와 Mirror에서 포크하여 전문 서버 개발자들이 새롭게 제작한 Mirage

 

Mirror의 특징

1. HLAPI, Mirror를 사용하는 개발자들은 서버 엔진 단의 작동방식을 모르고 api만 잘 활용하면 손쉽게 멅이플레이를 구현가능

 

2. Low level의 Transport를 지원 , Mirror은 초기에 TCP베이스로 탄생하였으나 게임에 맞는 다른 Transport를 사용하면 

자동으로 성능최적화가 가능 ex) 빠른 페이스의 게임(액션,스포츠)에서는 TCP보다 UDP를 이용하기 좋은데 원하는 Low level의 통신(전송)을 mirror에서는 쉽게 적용가능

728x90
728x90

1. Manifest에 권한설정

<uses-permission android:name="android.permission.SEND_SMS"/>

 

<Manifest 전체 소스코드>

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.whoami">

    <uses-permission android:name="android.permission.SEND_SMS"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.WhoAmI">
        <activity android:name=".MainActivity"
            android:exported="true">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

2. SEND_SMS 권한 확인,요청

 

public void OnCheckPermission(){

    Log.d("jinsoltest","실행1");
    if(ActivityCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED
        || ActivityCompat.checkSelfPermission(this,Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED){

        if(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.SEND_SMS)){
            Toast.makeText(this, "앱 실행을 위해서는 권한을 설정해야 합니다",Toast.LENGTH_SHORT).show();

            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.SEND_SMS, Manifest.permission.SEND_SMS},
                    PERMISSIONS_REQUEST
                    );
        } else{


            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.SEND_SMS, Manifest.permission.SEND_SMS},
                    PERMISSIONS_REQUEST);
        }
    }
}
728x90
728x90

https://www.youtube.com/watch?v=9l3uNWZOmTw 

 

대학교를 다니다 보면 항상 수강 신청하는 날이 무섭고 되게 떨립니다.

한 과목 한 과목 놓치면 자신의 공강이 사라지거나 , 점심시간이 사라지기도 하며

외롭게 혼자 학교를 다니게 될 수도 있으니까요

 

여기서 컴퓨터에 대해 조금 배우신분들이라면 분명 웹을 통해 수강신청서버와 통신을 하기때문에

코딩을 통해 똑같이 수강신청 서버가 열렸을때 서버로 수강신청 요청을 보내게되면

남들이 수강신청 서버에 접속이 몰릴때 , 따로 웹을통해 접속하지않고도

서버가 열리자마자 수강신청을 넣을수있습니다.

 

 

 

준비


수강신청 Requests 과정은 다음과같습니다.

 

수강신청을 하기전 대학교에 장바구니를 담는 날이 있습니다.

이때 Requests URL과 Cookies값들을 알아내고

과목별 Payload 딕셔너리 값들을 모두 알아내야 합니다.

 

Requests URL과 Payload값은 거의 변할일이 없지만

저희 학교같은경우 Cookies값의  SGJESSIONID값이 로그인할때마다 바뀌었습니다.

 

 

 

 

 

실습

크롬 F12(개발자모드)를 킨 상태에서 Network를 누른다음 

수강신청페이지(장바구니) 에 들어가서 아무과목이나 신청(or 장바구니담기) 버튼을 누릅니다.

그러면 Network 탭을 통해 모든 HTTP통신 과정을 볼 수 있습니다.

여기서 수강신청이 되는 요청과정이 분명있습니다.

저희학교같은경우 aply.do 였으며 

아주대의 경우 수강신청버튼을 눌러도 바로 수강신청서버로 요청이 가지않고

수강신청버튼클릭(요청) -> 보안문자 입력폼(응답) -> 옳게입력했을경우 수강신청서버로 수강신청Requests

 

네트워크 통신과정을 보면

capchaAnswer.action 이 보안문자 통신부분 ( payload값이 보안문자 입력값으로 전달됨) 옳바르게 입력했을경우

Response로 200값이 응답이 오게되고 바로 saveOpenLectureReg.ajax 를 통해 아주대 수강신청서버로 수강신청요청을 날리는것 같다.

 

 

 

 

 


 

 

 

 

 

 

 

 

한과목 수강신청 요청을 날리는 코드를 파이썬으로 짜봤다

우리학교의경우 보안문자 입력같은것이 없기때문에 되게 쉽게 구현이 가능함

다른학교들의경우 보안문자만 잘 해결하면 비슷비슷할거같다

 

실습코드(사회봉사 1학점짜리 수강신청코드)


import requests
import time

url='https://sugang.smu.ac.kr/UcrTlsn/aply.do'

cookies = {
    '_ga':'GA1.3.1726804677.1643137138',
    'WMONID':'jNFh1awnyxs',
    'SGJSESSIONID':'o153YzYsXcjHkQGgCaxr45rfQLQin1k44Zy2nuaxuPqvoQEW7x7qttHuS2NgtTAH.amV1c19kb21haW4vc3VnYW5nMQ=='
}

data = {
    '_AUTH_MENU_KEY': '',
'@d1#strSchYear': '2022',
'@d1#strSmtRcd': 'CMN002.0010',
'@d1#strSesRcd': 'CMN111.0000',
'@d1#strEstDeptCd': '00000',
'@d1#strEstShyr': '9',
'@d1#strSbjNo': 'HBRA1005',
'@d1#strDivcls': '1',
'@d1#strReTlsnSchYear': '',
'@d1#strReTlsnSmtRcd': '',
'@d1#strReTlsnSesRcd': '',
'@d1#strReTlsnSbjNo': '',
'@d#': '@d1#',
'@d1#': 'dmParamAply',
'@d1#tp': 'dm'
}

res = requests.post(url=url,cookies=cookies,data=data)
print("상태코드 :  " +  str(res))
print("수강신청요청결과  : " +  res.text)

 

위 코드를 수강신청 서버가 열릴시간때쯤 반복문을통해 요청을 보내면 빠르게 수강신청이 가능하다.

 

 

https://www.youtube.com/watch?v=9l3uNWZOmTw 

 

 

728x90
728x90

https://ititit1.tistory.com/114

 

CBT 바이낸스 리더보드 카피트레이딩 플랫폼 출시 / 비트겟 카피트레이딩 후기,단점)

카피트레이딩이란 쉽게 설명하면 내 계좌의 매수매도 권한 카피트레이더에게 맡겨 카피트레이더가 매수하면 똑같이 매수하고 매도하면 똑같이 매도하는 시스템입니다. 카피트레이딩은 아무래

ititit1.tistory.com

 

1. 호반꿀

호반꿀은 "박호두 반대로 하면 꿀빤다"의 약자입니다.

박호두는 해외선물,코인 선물 매매 방송(요즘은 코인만 합니다)을 하는 유튜버로 구독자는 35만명 가량 된다. 

 

 

2.호반꿀로 10억 벌고 경제적 자유를 달성한 박호두의 편집자

박호두 유튜브의 1등 공신 중 하나인 편집자 호튜브. 그 또한 투자 초장기에 박호두 반대매매-호반꿀 매매법으로 굉장히 이득을 많이 보았다고한다. 결국 가상화폐 투자로 10억을 넘게 벌고 현재는 편집자일을 그만두었다고함. 나중에 박호두 카페를 통해서 포르셰를 구매하여 인증하기도 했다.

 

 

제가 개발한 CBT 카피트레이딩 앱은 바이낸스 리더보드(랭킹)에서 원하는 트레이더를 골라

똑같이 매매를 진행하는 카피트레이딩 플랫폼인데요. 박호두 반대매매 시스템도 재미있을것 같아서 추가하였습니다.

 

 

자세한 내용은 아래링크로 가셔서 한번 읽어보시는걸 추천드립니다.

 

 

https://ititit1.tistory.com/114

 

CBT 바이낸스 리더보드 카피트레이딩 플랫폼 출시 / 비트겟 카피트레이딩 후기,단점)

카피트레이딩이란 쉽게 설명하면 내 계좌의 매수매도 권한 카피트레이더에게 맡겨 카피트레이더가 매수하면 똑같이 매수하고 매도하면 똑같이 매도하는 시스템입니다. 카피트레이딩은 아무래

ititit1.tistory.com

 

728x90
728x90

https://console.firebase.google.com/

 

로그인 - Google 계정

하나의 계정으로 모든 Google 서비스를 Google 계정으로 로그인

accounts.google.com

파이어베이스에서 데이터베이스를 만든 후 규칙을 다음과같이 허용해준다.

 

{
  "rules": {
    ".read": "true",
    ".write": "true"
  }
}

 

 

그 후 필드가 kind / name인 zoo테이블을 만든다.

 

 

 

 

그리고 animal 클래스를 만들어준다

 

//테이블이라고 생각하고, 테이블에 들어갈 속성값을 넣기
//파이어베이스는 RDBMS와 다르기 때문에 테이블이라는 개념이 없음. 원래는 키값이라고 부름
public class animal {
    String name; //동물 이름
    String kind; //동물 종류

    public animal(){} //이건 기본적으로 쓰더라구요.


    //get, set 함수는 커스텀 리스트 뷰를 사용하시는 분들과.. 필요하신 분만 작성하시면 좋습니다.
    public String getname() {
        return name;
    }

    public void setname(String name) {
        this.name = name;
    }

    public String getkind() {
        return kind;
    }

    public void setkind(String kind) {
        this.kind = kind;
    }

    //값을 추가할때 쓰는 함수, MainActivity에서 addanimal함수에서 사용할 것임.
    public animal(String name, String kind){
        this.name = name;
        this.kind = kind;
    }
}

 

 

 


데이터베이스 저장

 

 

이제 메인엑티비티에서 데이터베이스를 연동해줌 //전역변수로정의

 

// 파이어베이스 데이터베이스 연동
private final FirebaseDatabase database = FirebaseDatabase.getInstance();

//DatabaseReference는 데이터베이스의 특정 위치로 연결하는 거라고 생각하면 된다.
//현재 연결은 데이터베이스에만 딱 연결해놓고
//키값(테이블 또는 속성)의 위치 까지는 들어가지는 않은 모습이다.
private final DatabaseReference databaseReference = database.getReference();

 

public void addanimal(String name, String kind) {
    Log.d("jinsoltest","애니멀함수 ");
    //여기에서 직접 변수를 만들어서 값을 직접 넣는것도 가능합니다.
    // ex) 갓 태어난 동물만 입력해서 int age=1; 등을 넣는 경우

    //animal.java에서 선언했던 함수.
    animal animal = new animal(name,kind);

    //push()는 값을 넣을때 상위 키값을 랜덤으로 설정해 주는 함수입니다.
    //채팅기능을 만들때 사용하면 좋습니다.
    databaseReference.child("zoo").push().setValue(animal);
    //Toast.makeText(context,"db전송 :"+edit1.getText().toString()+" , "+edit2.getText().toString(),Toast.LENGTH_SHORT).show();

}

 


데이터베이스 읽기

 


public void ReadAnimal(){
    FirebaseDatabase.getInstance().getReference().addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                Log.d("jinsoltest", "ValueEventListener : " + snapshot.getValue());
            }
        }


        @Override
        public void onCancelled(@NonNull DatabaseError error) {

        }
    });

}

 

Log가 잘찍힌것을 확인할수있다.

728x90
728x90

Fragment와 Activity에서 버튼이벤트를 발생시키는것은 조금 다르다. (Fragment는 android:onClick)를 사용x )

 

프래그먼트에서는 OnClickListener를 상속받아서 구현해줘야함. onClick메소드를 오버라이드 해줘야함

 

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    Log.d("jinsoltest","oncreateview 설취");
    View view = inflater.inflate(R.layout.fragment_search,container,false);
    edit1 = (EditText) view.findViewById(R.id.edit1);
    edit2 = (EditText) view.findViewById(R.id.edit2);
    Button btn_test = (Button) view.findViewById(R.id.btn_jinsol);

    btn_test.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            addanimal(edit1.getText().toString(),edit2.getText().toString());
        }
    });
    //이부분 중요
    return view;
}

 

이런식으로 코드를 짯을때 버튼이벤트가 발생하지않는다면

 

다음과같이 상속을받아 구현해보자.

 

 

public class SlideshowFragment extends Fragment implements View.OnClickListener {

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {

        View root = inflater.inflate(R.layout.fragment_slideshow, container, false);


        Button btn123 = root.findViewById(R.id.button1);
        btn123.setOnClickListener(this);
                
    }


    @Override
    public void onClick(View v) {
        switch(v.getId())
        {
            case R.id.top_layout:
            {
                if(isAvisiable) layout1.setVisibility(View.GONE);
                else layout1.setVisibility(View.VISIBLE);
                break;
            }

        }
    }
}

 

728x90
728x90

회원가입


 

0. 반드시 파이어베이스와 앱과 연동되어있어야함

 

1. 파이어베이스에 접속하여

 

Authemtication에서 이메일/비밀번호의 상태를 반드시 사용설정됨으로 수정

 

2. 

 

전역변수로 FirebaseAuth 변수 생성

private FirebaseAuth firebaseAuth;

 

OnCreate함수 안에서 

firebaseAuth = FirebaseAuth.getInstance();

if(email.length() > 8){
                    Log.d(TAG,"등록 버튼" + email + " , " + pwd);
                    final ProgressDialog mDialog = new ProgressDialog(register.this);
                    mDialog.setMessage("가입중입니다....");
                    mDialog.show();

                    //파이어베이스에 신규계정 등록하기
                    firebaseAuth.createUserWithEmailAndPassword(email,pwd).addOnCompleteListener(register.this, new OnCompleteListener<AuthResult>() {
                        @Override
                        public void onComplete(@NonNull Task<AuthResult> task) {

                            //가입 성공시
                            if(task.isSuccessful()){
                                mDialog.dismiss();

                                FirebaseUser user = firebaseAuth.getCurrentUser();
                                String email = user.getEmail();
                                String uid = user.getUid();


                                //해쉬맵 테이블을 파이어베이스 데이터베이스에 저장
                                HashMap<Object,String> hashmap = new HashMap<>();

                                hashmap.put("uid",uid);
                                hashmap.put("email",email);

                                FirebaseDatabase database = FirebaseDatabase.getInstance();
                                DatabaseReference reference = database.getReference("Users");
                                reference.child(uid).setValue(hashmap);

                                Intent intent = new Intent(register.this, MainActivity.class);
                                startActivity(intent);
                                finish();
                                Toast.makeText(register.this,"회원가입에 성공",Toast.LENGTH_SHORT).show();

                            }else{
                                mDialog.dismiss();
                                Toast.makeText(register.this, "이미 존재하는 아이디 입니다.", Toast.LENGTH_SHORT).show();
                                return; //해당 메소드 진행을 멈추고 빠져나감
                            }
                        }
                    });

                }else{
                    Toast.makeText(register.this, "올바른 이메일 주소를 입력해주세요", Toast.LENGTH_SHORT).show();
                    return;
                }

 


 

firebaseAuth.createUserWithEmailAndPassword.(이메일,패스워드).addOnCompleteListener(activity, OnCompleteListener<AuthResult>())

 

 

addOnCompleteListener

 

FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();

UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
        .setDisplayName("Jane Q. User")
        .setPhotoUri(Uri.parse("https://example.com/jane-q-user/profile.jpg"))
        .build();

user.updateProfile(profileUpdates)
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                if (task.isSuccessful()) {
                    Log.d(TAG, "User profile updated.");
                }
            }
        });

 

 

 


로그인

 

String email = mEmailText.getText().toString().trim();
String pwd = mPasswordText.getText().toString().trim();
firebaseAuth.signInWithEmailAndPassword(email,pwd).addOnCompleteListener(MainActivity.this, new OnCompleteListener<AuthResult>() {
    @Override
    public void onComplete(@NonNull Task<AuthResult> task) {
        if(task.isSuccessful()){
            Intent intent = new Intent(MainActivity.this, CopyTrade.class);
            startActivity(intent);
        }else{
            Toast.makeText(MainActivity.this,"로그인 실패",Toast.LENGTH_SHORT).show();
        }
    }
});

 

 

 

728x90
728x90

 

 

서론


안녕하세요 앞으로 Flutter에 대해 공부하도록 하겠습니다.

 

Flutter는  앱 뿐만아니라 웹페이지,윈도우 데스크탑 프로그램도도 만들수있으며

배우기 쉽고, 개발언어가 구글에서 만든 Dart언어인데 앱개발시 Dart언어 단 하나만 배우면 된다는 장점이있습니다.

 

글을 읽기 전에 저는 컴공과에 재학중인 대학생입니다. 따라서 글에 틀린부분이 있을수 있다는점 양해 부탁드립니다.

 

 

 

설치


https://flutter-ko.dev/docs/get-started/install/windows#

 

윈도우에서 설치

 

flutter-ko.dev

 

이 사이트에 들어가서 Flutter SDK를 다운받아야되는데 저같은경우 다운로드 버튼이 Failed로 돼있어서 다운로드가 불가능하였습니다.

해결방법은 플러터 공식사이트https://flutter.dev/ 로 접속해서 다운받는 방식입니다...(간단)

 

그 후 환경변수에 들어가셔서  Path에 추가해주셔야 되는데

flutter에서 압축을 해제하여 flutter폴더에있는 bin폴더의 경로를 추가해주면됩니다.

 

그 후 안드로이드 스튜디오는 설치되어있다고 가정하고

 

안드로이드 스튜디오에서 flutter 플러그인 설치하시면 끝입니다.

 

설치과정을 영상으로 자세히 보고싶으신분은 코딩애플님의 영상을 추천드립니다.

 

https://www.youtube.com/watch?v=JS-Si5GO3iA 

 

실습


1. Hello World ! 

 

- Flutter에서는 화면을 그리는 모든 디자인 요소를 위젯(Widget)이라고 함

 

플러터는 lib/main.dart가 메인 화면입니다.

코딩의 시작 Hello World를 화면에 표시하고싶으시면

 

#appbar의 title은 Welcome to Flutter
#center의 text는 Hello World로 바꾼 코드 

Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Welcome to Flutter'),
        ),
        body: Center(
          child: Text('Hello World'),
        ),
      ),
    );
  }
}

 

 

2. 외부 패키지 이용하기

 

플러터의 의존성은 pubspec.yaml파일이 담당합니다.

 

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.2
  english_words: ^3.1.0

cupertino는 UI가 IOS스러운 앱을 만들때 사용하는 디자인

종속성을 추가해준다음 Pub get을 해줘야함

 

패키지를 가져올때 import 를 사용함.

lib/main.dart 파일에 다음과같이 패키지를 가져와준다

import 'package:english_words/english_words.dart';

 

 

"Hello World" 문자열출력대신 English words를 사용하여 텍스트를 생성해보도록 합시다.

 

@override
Widget build(BuildContext context) {
  final wordPair = WordPair.random();
  return MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: const Text('Welcome to Flutter'),
      ),
      body: Center(
        child: Text(wordPair.asPascalCase),
      ),
    ),
  );
}

 

Stateful 위젯 추가하기

 

Stateless 위젯은 모두 변경불가능함. 즉 모든값이 final 이다.

 

Stateful 위젯은 위젯의 수명동안 변경될 수 있는 상태를 유지합니다. Stateful 위젯은 최소 두 개 이상 클래스가 필요합니다: 1) StatefulWidget 클래스가 2) State 클래스 의 인스턴스를 생성합니다. StatefulWidget 클래스 그자체는 변경불가능합니다. 하지만 State 클래스가 위젯의 수명동안 상태를 유지합니다.

 

앱의 수명동안 변경될수있는 위젯 RandomWords를 추가하고 그위젯에서 State클래스인 RandomWordsState를 생성할것이다. 그 후 RandomWords를 기존 Stateless위젯 MyApp 의 자식으로 사용될 것임

 

 

class RandomWordsState extends State<RandomWords> {
  // TODO Add build() method
}

 

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}

 

Randomwordsstate 수정

class RandomWordsState extends State<RandomWords> {
  @override
  Widget build(BuildContext context) {
    final wordPair = WordPair.random();
    return Text(wordPair.asPascalCase);
  }
}

 

 

전체코드

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_plugin2/flutter_plugin2.dart';
import 'package:english_words/english_words.dart';

void main() {
  runApp(const MyApp());
}



class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}



class _MyAppState extends State<MyApp> {


  String _platformVersion = 'Unknown';

  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    String platformVersion;
    // Platform messages may fail, so we use a try/catch PlatformException.
    // We also handle the message potentially returning null.
    try {
      platformVersion =
          await FlutterPlugin2.platformVersion ?? 'Unknown platform version';
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });
  }

  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Welcome to Flutter'),
        ),
        body: Center(
          child: RandomWords(),
        ),
      ),
    );
  }
}

class RandomWordsState extends State<RandomWords> {
  @override
  Widget build(BuildContext context) {
    final wordPair = WordPair.random();
    return Text(wordPair.asPascalCase);
  }
}

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}

 

 

이렇게 코드를 짜시면 앱이 실행될때마다 중앙화면에 영단어가 랜덤으로 출력됩니다.

 

리스트뷰를 이용한 랜덤 영단어 생성기

 

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_plugin2/flutter_plugin2.dart';
import 'package:english_words/english_words.dart';

void main() {
  runApp(const MyApp());
}



class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}



class _MyAppState extends State<MyApp> {


  String _platformVersion = 'Unknown';

  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    String platformVersion;
    // Platform messages may fail, so we use a try/catch PlatformException.
    // We also handle the message potentially returning null.
    try {
      platformVersion =
          await FlutterPlugin2.platformVersion ?? 'Unknown platform version';
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });
  }

  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('My Project01'),

        ),
        body: RandomWords(),
      ),
    );
  }
}

class RandomWordsState extends State<RandomWords> {

  final _suggestions = <WordPair>[];
  final _biggerFont = const TextStyle(fontSize:18.0);

  Widget _buildSuggestions() {
    return ListView.builder(
        padding: const EdgeInsets.all(16.0),
        itemBuilder: /*1*/ (context, i) {
          if (i.isOdd) return Divider(); /*2*/

          final index = i ~/ 2; /*3*/
          if (index >= _suggestions.length) {
            _suggestions.addAll(generateWordPairs().take(10)); /*4*/
          }
          return _buildRow(_suggestions[index]);
        });
  }

  Widget _buildRow(WordPair pair) {
    return ListTile(
      title: Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final wordPair = WordPair.random();
    return Scaffold(

      body: _buildSuggestions(),
    );
  }
}

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}

 

 

본글은 

https://flutter-ko.dev/docs/get-started/codelab  를 참고하여 작성함

728x90
728x90

실습은 리눅스 Ubuntu 가상환경에서 진행됩니다. 

 

 

SCAPY 란?


Scapy는 패킷 조작 프로그램으로 다양한 프로토콜의 패킷을 생성/전송/캡처 작업을 수행할수 있으며

hping,nmap의 85% arpspoof, arp-sk, tcpdump, tethereal, p0f등을 대체 할수있습니다.

 

 

Scapy 설치페이지


https://scapy.readthedocs.io/en/latest/

 

Welcome to Scapy’s documentation! — Scapy 2.4.5. documentation

© Copyright 2008-2021 Philippe Biondi and the Scapy community. Revision 7e161f1d.

scapy.readthedocs.io

 

실습을 위한 기본 개념 + Scapy 실습 환경 구축


스캔(Scan): 서버의 작동 여부와 서버가 제공하는 서비스를 확인

 

 

국내에서 스캐닝은 불법입니다. 절대로 공개되어 있는 IP/도메인에 대해 스캐닝하면 안됨

제48조(정보통신망 침해행위 등의금지) 

 

Scapy 실습 환경 구축(리눅스 환경 cmd)

> sudo apt-get update

> sudo apt-get upgrade

> sudo scapy

> sudo apt-get install scapy

> sudo apt-get upgrade scapy

 

#기본명령어

ls() # Layer 리스트 보여줌

ls(TCP)  #TCP header 구조

ls(IP) #IP header 구조

lsc() #scapy 명령어/함수리스트 

conf #환경설정

sniff() #패킷 스니핑

str() #문자열 정보보기

hexdump() #16진수 코드보기

traceroute("naver.com") #hop 추적

 

 

Scapy 실습(패킷 생성과 전송)


CMD에서 scapy 명령어를 통해 scapy실행

 

 

 

frame=Ether()/IP()/TCP()/Raw(load="heelo")

frame.show()

frame=Ether()/IP(ttl=20)/TCP()/Raw(load="hi")

frame.show()

str(frame) #16진수 문자열출력

hexdump(frame) #16진수 덤프

 

#SYN/ACK Packet 
> pkt =IP(dst="192.168.122.101")/TCP(dport=80,flags="SA)

#ICMP Packet
pkt = IP(dst=192.168.122.101")/ICMP(code=1,type=3)

#icmp packet , echo request packet
mypkt = IP(dst=192.168.122.101")/ICMP(code=0,type=8)

mypkt.summary()#패킷 한줄요약
mypkt.show()#패킷정보출력

#캡처한 패킷을 pcap 쓰기
wrpcap("file1.pcap", mypkt)
a = rdpcap("file1.pcap") #읽기
728x90
728x90

DoS(Denial of Service atack) : 혼자 쏘는 Dos공격

 

▶한 명 또는 그 이상의 사용자가 1개의 시스템의 리소스를 독점하거나 파괴함으로써

시스템 또는 서비스의 정상적인 운영을 할 수 없게 만드는 공격

 

▶시스템파괴, 시스템 자원 및 네트워크 자원 고갈

 

DDoS : 분산 Dos 공격

 

▶ Dos 공격의 일종 여러 대 공격자를 분산적으로 배치하여 동시에 DoS공격

▶ 여러 대의 컴퓨터를 일제히 동작하게 하여 특정사이트를 공격하는 방식

 

 

DoS공격 개념

 

▶ 자원 고갈형 

ex) SYN Flooding , Ping of Death , L7 Application공격(http get flooding)

 

▶ OS 또는 서버 프로그램, 네트워크 프로토콜의 취약점을 이용한 Dos

Land attack , Ping of Death Attack , Teradrop Attack

 

▶ Route 경로 조작

ICMP Router Discovery Attack

 

▶ Bandwidth 잠식형

Smurf Attack , UDP Diagnostic Port Denial service attack

 

SYN Flooding : 서버 자원의 리소스를 고갈시키는 공격

 

'SYN Received' 상태로 ACK 패킷을 기다리는것을 'BACKLOG에 빠졌다' 라고 말함

 

SYN FLOODING 과정

1. 공격자는 많은 숫자의 SYN패킷을 서버에 전송

2. 서버는 받은 SYN 패킷에 대한 SYN/ACK 패킷을 각 클라이언트로 보냄

3. 서버는 자신이 보낸 SYN/ACK 패킷에 대한 ACK패킷을 받지못함

4. 서버는 세션의 연결을 기다리게 되고 공격은 성공

 

SYN FLOODING 보안대책 -> 시스템 패치설치, 침입 차단,탐지 시스템 설치, IP주소 대역 차단, SYN_COOKIE 이용

 

 

Boink, Bonk, Teardrop : TCP 프로토콜의 오류제어를 이용한 공격

 

Bonk : 처음 패킷을 1번으로 보낸후 두번째와 세번째 패킷의 시퀀스 넘버를 모두 1번으로 조작해서 보냄

BOINK : 처음 패킷을 1번으로 보낸후 두번째 패킷은 101번, 세번째 패킷은 201번 으로 정상적으로 보내다가 중간에서 일정한 시퀀스 넘버를 보냄

Teardrop : 시퀀스 넘버를 일정하게 바꾸는 것을 넘어 중첩과 빈공간을 만들어 시퀀스 넘버가 좀더 복잡해지도록 섞음

 

▷ 전혀 맞지 않는 시퀀스 넘버때문에 피해 시스템이 패킷화된 데이터를 재조합하는데 혼란이 생겨 cpu에 과부하가 걸리게 됨

 

LAND 공격 : SYN Flooding 기법과 유사

 

송신지 IP주소를 스푸핑하여 SYN flooding 공격 이때 패킷을 전송할때 출발지ip주소와 목적지 ip주소의 값을 동일하게

 

수신 시스템은 송신지 주소가 자신의 주소와 동일하므로 응답패킷을 자신에게 송부하고 유휴시간까지 대기하게 되어 해당 시스템에 장애 발생

 

Land 공격법은 동시 사용자 수를 점유하여 cpu부하까지 올림

 

 

Smurf공격 

 

웹 Dos공격

 

Http 유형 http get flooding , 동적 http requests flooding , http cc attack , http slowloris , rudy

dns 유형 dns query flooding , dns application ddos

메일 유형  mail bomb

728x90

+ Recent posts