1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Htonl{
    public static void main(String args[]){
        if(args.length<1){
            System.out.println("Usage : java Htonl");
            System.exit(0);
        }
 
        int value=Integer.parseInt(args[0]);
        int newValue=swap(value);
 
        System.out.println("big endian value : 0x" + Integer.toHexString(value));
        System.out.println("little endian value : 0x" + Integer.toHexString(newValue));
    }
 
    /*
     * Swapping byte orders of given numeric types
     */
    static short swap(short x){
        return (short)((x << 8) | ((x >> 8) & 0xff));
    }
 
    static char swap(char x){
        return (char)((x << 8) | ((x >> 8) & 0xff));
    }
 
    static int swap(int x){
        return (int)((swap((short)x) << 16) | (swap((short)(x >> 16)) & 0xffff));
    }
 
    static long swap(long x){
        return (long)(((long)swap((int)(x)) << 32) | ((long)swap((int)(x >> 32)) & 0xffffffffL));
    }
 
    static float swap(float x){
        return Float.intBitsToFloat(swap(Float.floatToRawIntBits(x)));
    }
 
    static double swap(double x){
        return Double.longBitsToDouble(swap(Double.doubleToRawLongBits(x)));
    }
}

'Programing > java' 카테고리의 다른 글

간단한 랜덤함수 사용법  (0) 2015.04.29
stream read하기  (0) 2015.02.18
java Mashalling과 Serialization의 차이  (0) 2015.01.31
Java Serializable : 자바 직렬화  (0) 2015.01.31
thread이야기_02.run()과 start()의 차이  (0) 2014.11.23
Posted by duehd88
,

Marshalling과 Serialization을 유사하다고 한다. 위키피디아에 따르면 파이썬 표준라이브러리에서는 직렬화와 마샬링은 동일하게 간주된다고 한다. 포트란에서도 동일하게 본다. 근데 자바에서는 굳이 구분하는데 뭐가 다를까?

Marshalling은 코드베이스를 기록하지만 직렬화는 하지않는 점이 다르다고 한다. 즉 원격 프로시저를 호출하는 것에서는 유사하지만 다른 목적을 가졌다는 것이다. Marshaling은 원격 프로시저를 호출할때 함수의 parameter, return value들을 전달할 수 있는데 반해 Serialization은 구조화된 데이터를 byte stream과 같은 형식으로 복사하는 것을 의미한다.

이해하기가 어렵다. 쉽게 이야기하면 직렬화는 객체 자체를 복사하는 개념이고 마샬링은 코드베이스를 가져와 만드는 개념이다.

그래서 객체를 이용하지 않는 다른 언어 또는 플랫폼간의 통신할때 주로 Marshaling을 과정을 통한다. 그리고 네트워크나 객체 싱크에는 Serialization을 많이 이용한다.

Posted by duehd88
,

 Java Serializable : 자바 직렬화
  자바는 컴파일 후 생성된 .class파일은 우리가 만든 클래스의 정보를 담고 있다. 이는 class라는 하나의 데이터 타입이라고 볼 수 있다. 이 .class의 바이트가 가상머신에서 우리가 만들었던 클래스로 로딩되고 그 정보를 보고 객체(instanse)를 생성한다. 그리고 그 객체에 맞는 메모리가 할당된다. 아무튼 이 가상머신 내부에 존재한는 객체 메모리를 저장하거나 네트워크로 전송하기 위해서 한 줄로 이어진 바이트의 형태를 만드는 것, 그러니까 바이트 스트림을 만들어내는 것을 객체 직렬화라고 한다. 또한 보안같은 특별한 이유로 특정값을 직렬화에서 제외할 수 있는데 이것은 transient제어자를 붙이면 된다.


  직렬화 방법은 두가지가 있다. Serializable 또는 Externalizable이라는 Interface를 implements하여 구현할 수 있다. 두가지의 차이를 간단히 설명하자면 Serializable는 데이터의 저장과 복구가 자동으로 이루어진다. Externalizable 직렬화 권한은 주지만 데이터의 저장 및 복구 방법을 사용자가 구현해야한다.


 

아래 예제는 예전에 공부하면서 따라했던 코드이다.

 

Serializable예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SerialObject implements Serializable{
    private String name;
    private String dept;
    private String title;
 
    public SerialObject (String name, String dept, String title){
        this.name = name;
        this.dept = dept;
        this.title = title;
    }
 
    public String toString(){
        return name + ":" + dept + ":" + title;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
public class SerialObjectTest{
    public static void main(String[] args) throws Exception{
        FileOutputStream fos = new FileOutputStream("object.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
 
        SerialObject so1 = new SerialObject("갑""노동부""부장");
        SerialObject so2 = new SerialObject("을""노동부""신입");
 
        oos.writeObject(so1);
        oos.writeObject(so2);
        oos.close();
 
        FileInputStream fis = new FileInputStream("object.txt");
        ObjectInputStream ois = new ObjectInputStream(fis);
 
        SerialObject rso1 = (SerialObject)ois.readObject();
        SerialObject rso2 = (SerialObject)ois.readObject();
 
        System.out.println(rso1.toString());
        System.out.println(rso2.toString());
        ois.close();
    }
}

 

Externalizable예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ExternalObject implements Externalizable{
    private String name;
    private int age;
    private float height;
 
    public ExternalObject(String name, int age, float height){
        this.name = name;
        this.age = age;
        this.height = height;
    }
 
    public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException{
        name = (String)oi.readObject();
        age = oi.readInt();
        height = oi.readFloat();
    }
 
    public void writeExternal(ObjectOutput oo) throws IOException{
        oo.writeObject(name);
        oo.writeInt(age);
        oo.writeFloat(height);
    }
 
    public String toString(){
        return "이름:"+name+", 나이:"+age+ ", 키:"+height;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ExternalObjectTest{
    public static void main(String[] args) throws IOException, ClassNotFoundException{
        FileOutputStream fos = new FileOutputStream("external.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
 
        ExternalObject so1 = new ExternalObject("갑",43,170.25f);
        ExternalObject so2 = new ExternalObject("을",26,190.01f);
 
        oos.writeObject(so1);
        oos.writeObject(so2);
        oos.close();
 
        FileInputStream fis = new FileInputStream("external.txt");
        ObjectInputStream ois = new ObjectInputStream(fis);
 
        ExternalObject rso1 = (ExternalObject)ois.readObject();
        ExternalObject rso2 = (ExternalObject)ois.readObject();
 
        System.out.println(rso1.toString());
        System.out.println(rso2.toString());
        ois.close();
    }
}

위의 코드들에는 문제가 한가지 있다. serialVersionUID가 없다.

serialVersionUID는 명시적으로 선언해주면 InvalidClassException을 피할 수 있다. 컴파일러마다 다른계산법에 의해 serialVersionUID의 default값이 변화할 수 있기 때문이다. 또 serialVersionUID는 클래스 내부에서만 이용되므로 private 키워드를 붙여주는 것을 권고한다.

Posted by duehd88
,

W/System.err(5490): java.net.ConnectException: failed to connect to /192.168.123.103 (port 5505): connect failed: ETIMEDOUT (Connection timed out)

 

간혹 위의 에러를 이해할 수 없을 때가 있을 것이다. 주소도 잘 맞췄고 포트도 틀리질 않았는데 왜 안되는가? 구체적인 시나리오는 공인 IP한대에 공유기가 물려있고 그 공유기 아래에 또 다른 공유기가 물려있다. 하지만 포트포워딩을 쓰기 귀찮아서 같은 공유기내에서 각각 사설 IP를 물려받아 데스크탑에 서버를 열고 안드로이드 클라이언트를 물렸다. 그런데 왜 ConnectException이 뜰까?

 

아이피와 포트번호가 틀리지 않았다면 보통 이런 문제는 방화벽등으로 막혀있거나 라우터테이블 같은 곳에서 ip를 찾을 수 없는 문제라고 볼 수 있다. 근데 나는 방화벽 설정도 문제가 없을뿐더러 공유기 내부에 두개(서버와 클라이언트)가 물려있어서 ㅄ이 아닌이상 아이피와 포트번호를 헷갈린 문제도 아니었다. 만약 그랬더라면 바로 찾았을터... 정말 방화벽도 내가 실수한 것도 아니라면 한번 간단하게 분석해보자!

 

우선적으로 우리가 통신하는 것에 대한 이해가 필요할듯 하다. 네트워크에서 통신을 할때 상대의 IP주소도 알아야하지만 실제적으론 MAC 주소를 알아야 통신할 수 있다. 하지만 "IP는 알 수 있어도 MAC주소는 어떻게 제공받는가?"라는 문제가 생긴다. 그래서 ARP(Address Resolution Protocol)가 존재한다. 그리고 이를 통해 통신할 상대의 MAC주소를 가져오고 관리하는 것이다. 그리고 이 MAC주소를 ARP table이란놈으로 관리를 하는데 윈도우 도스창 또는 리눅스의 터미널에서 에서 arp명령어로 간단히 알 수 있다. 그러면 처음에 MAC주소를 어떻게 얻어올까? 바로 IP주소를 통해 MAC주소를 알아온다. 나와 통신할 상대ip주소를 ARP packet에 담아 공유기(스위치)로 request메시지를 보내주면 공유기는 MAC주소를 ff.ff.ff.ff.ff.ff로 설정해서 연결된 모든 MAC주소로 ARP request 메시지를 Broadcasting한다. 그러면 상대의 IP가 일치하는 곳에서 response메세지로 상대 MAC주소가 오게 되고 이를 ARP table에 업데이트하고 업데이트된 후부터는 Unicasting되어서 사용하는 것이다.

 

그러니까 ip는 Logical Address로 라우팅을 위한(최단거리를 찾아가기위한) 목적을 가지고 있고 실질적인 통신은 Physical Address인 MAC Address로 상대방을 구분하여 통신을 하는 것이다. 그러므로 내가 ip와 port번호가 맞았다고 한들 MAC주소를 알아내지 못하니 통신이 불가능

한것...

 

이를 해결하기 위해 데스크탑 ARP table이든 안드로이드 ARP table이든 간에 서로의 MAC주소를 등록시켜줘야 하는 것인데 의문인 것은 위에서 설명했던것처럼 내가 이미 소켓 연결을 하려고 할때 이미 ARP table을 업데이트 하고 통신하는 것이 정상이다. 근데 왜 안되는 것일까?

 

------------------------------------------------------------------------------------------------------------------------------

결국 결론은 공유기 문제인것 같다. LG공유기로 바꾼 후 부터 인터넷이 자주 끊기는 문제가 잦았고 문제가 많았다. 아마 LG 공유기라서 이러한 문제가 있는것 같다. 기존의 공유기에서는 이러한 문제도 없었을 뿐더러 다른 집이나 학교의 공유기에선 전혀 문제가 없었다.

또 LG공유기에 사설 IP를 고정으로 할당하는 기능이 없다. 이런 쓰레기같은... 역시 LG는 디스플레이말곤... 노답이다.

Posted by duehd88
,

LayoutInflater로 레이아웃 교체하기

레이아웃 전체를 교체하거나 부분을 교체할때 LayoutInflater로 교체를 할 수 있다.
사용 방법은 주석으로 잘달아 놨으니... 걍 저렇게 쓰면 된다.

1
2
3
4
5
6
7
// activity_main.xml에서 정의한 LinearLayout 할당
LinearLayout inflated = (LinearLayout)findViewById(R.id.changed_layout);
// LayoutInflater 객체 생성
LayoutInflater inflater =  (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Inflated_Layout.xml로 구성한 레이아웃을 inflated영역(R.id.changed_layout)으로 교체
inflater.inflate(R.layout.new_layout, inflated);
 


Posted by duehd88
,

android.os.NetworkOnMainThreadException

정말 안드로이드 시스템의 기초적인 부분을 간과한 문제이다. MainThread에서 소켓통신을 행할 경우 Runtime error를 내품는다.

안드로이드에서 소켓통신은 Thread를 따로 만들어서 통신하자.

Posted by duehd88
,

우선 코드부터

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class MainThread{
    public static void main(String[] args){
        Thread mThread=Thread.currentThread();
        printThreadID(mThread.getName()+"-시작");
        
        Thread th1=new Thread(new RunInterface());
        Thread th2=new Thread(new RunInterface());
        Thread th3=new Thread(new RunInterface());
        Thread th4=new Thread(new RunInterface());
        
        th1.run();
        th2.run();
        th3.start();
        th4.start();
        
        printThreadID(mThread.getName()+"-종료");
    }
    
    protected static void printThreadID(String id){
        System.out.println(id);
    }
}
 
class RunInterface implements Runnable{
    @Override
    public void run(){
        Thread mThread=Thread.currentThread();
        MainThread.printThreadID(mThread.getName()+"-시작");
        for(int i=0;i<10;i++){
            MainThread.printThreadID(mThread.getName()+"-"+i);
        }
        MainThread.printThreadID(mThread.getName()+"-종료");
    }
}//RunInterface end
 

실행결과는 해보면 앎.

 

간단히 얘기하자면 각자 thread는 memory에서 stack을 call해서 이용한다. 이때 start()할 경우 개인의 thread를 만들고 개인의 call stack을 이용한다. 하지만 run()할 경우 thread를 만들고 thread를 만든 main thread의 context와 Thread-0,Thread-1의 context가 switching 되어 작업된다. 즉, run() method로 쓰레드를 사용할 경우 main thread의 call stack을 이용한다.

Posted by duehd88
,

하나의 process 내부에도 엄연한 작업 단위가 있다. 이를 thread라고 하고 요즘엔 당연 multi-threading 방식의 programming을 한다.

물론 여러 이슈에 따라서 single-threading방식이 더 유리한 경우도 있다는 거 알아두자!

(예를 들면 Android와 Node-js는 single-thread기반이다.)

 

 runInterface class

1
2
3
4
5
6
7
8
9
10
11
12
public class runInterface implements Runnable{
    @Override
    public void run(){
        Thread mThread=Thread.currentThread();
        System.out.printf("%s-시작\n",mThread.getName());
        for(int i=0;i<50;i++){
            System.out.printf("%s-%d\n",mThread.getName(),i);
        }
        System.out.printf("%s-종료\n",mThread.getName());
    }
}
 

 example class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class example{
    public static void main(String[] args){
        //currentThread() 메서드는 static 메서드이다.
        Thread mThread=Thread.currentThread();
        System.out.printf("%s-시작\n",mThread.getName());
        
        runInterface run=new runInterface();
        
        Thread thread1=new Thread(run);
        Thread thread2=new Thread(run);
        
        thread1.start();
        thread2.start();
        
        System.out.printf("%s-종료\n",mThread.getName());
    }
}
 

 실행해보자!

process가 돌때 main thread가 만들어지고 Thread-0과 Thread-1을 돌린다. 그리고 main thread는 바로 종료된다.

거의 main thread는 Thread-0과 Thread-1을 만들고 start 시켜준뒤 바로 종료 되었지만 Thread-0과 Thread-1을 계속 작업을 하는 것을 알 수 있다.

 

Posted by duehd88
,
왜 상수에는 #define보다 const를 쓰는 것이 좋다고 말하는가?

 

아니다. 단지 const는 "TYPE형을 지정할 수 있다는 것, scope rule을 준수하면서 상수를 이용할 수 있다." 라는 점과 "value의 주소를 얻고 reference로 쓸 수 있다." 는 장점이 있다. 그래서 scope내부에서만 이용하는 상수나 변수처럼 이용가능한 상수에 쓴다. 

 

#define은 scope가 아닌 global하게 사용될 상수이다. 단순히 #define은 전처리지시자로써 프로그램의 맨처음 윗단에 정의하고 코드내에서 문법적으로 맞다면 어디든 쓸 수 있다.

 

즉, 상황과 용도에 맞춰 쓰면 된다는게 나의 생각이다.

Posted by duehd88
,

- 윈도우 -

시스템변수에 JDK환경변수를 등록 : jdk가 설치된 경로를 환경변수를 등록한다. 이름은 맘대로... 대개 JAVA_HOME이라고 한다.

시스템변수에 Path 추가 : %JAVA_HOME%\bin;ADT Bundler가 있는 디렉토리\sdk\platform-tools;

시스템변수에 CLASSPATH 추가 : %JAVA_HOME%\lib\tools.jar;

 

요즘 개발하는 곳이 하도 바뀌어 간단하게 adt번들러로 구축한다. 구축하다가 깜빡하지 말자!

나만 알아볼수있어서...ㅈㅅ

해본사람은 저거만봐도 알수있을것이다...

Posted by duehd88
,