2013.07.05 11:28


그럼 MFC를 이용한 채팅 프로그래밍 시작하기(서버편) - 1에 이어서 계속 진행 하도록 하겠습니다.

앞서 말씀드린대로 남은 작업은 데이터 송수신을 위한 가상함수 재정의 부분과 대화상자 클래스에서 서버 소켓을 초기화 하고 데이터를 전송하는 부분입니다.

그럼 먼저 데이터 송수신을 위한 가상함수를 재정의 하도록 하겠습니다.
먼저 서버 소켓에 재정의 해야 하는 OnAccept() 함수를 보도록 하겠습니다.
서버 소켓은 클라이언트의 요청을 기다리는 대기 상태입니다. 이 때 클라이언트는 서버 IP주소와 포트번호로 서버에 접속 요청을 위해 Connect()함수를 호출합니다. OnAccept() 함수는 사용자의 이벤트에 의해서 호출되지 않고 클라이언트 소켓의 Connect() 함수를 통해서 호출됩니다. 따라서 이 메소드는 서버 소켓에서 재정의 되어야 하고 재정의된 함수 내부에는 연결을 받아들여 이를 자소켓에 연결해 두어야 합니다.

다음은 자소켓에 재정의 해야 하는 OnReceive() 함수 입니다.
클라이언트가 데이터를 송신하기 위해 Send() 함수를 호출하게 되면 자소켓의 OnReceive() 함수가 호출됩니다. 따라서 데이터를 수신하기 위한 ReceiveData()함수를 호출하도록 함수를 재정의 해야 합니다.

마지막으로 자소켓에 재정의 해야 하는 OnClose() 함수 입니다.
클라이언트 소켓이 닫히게 되면 OnClose() 함수가 호출됩니다. 따라서 클라이언트와 연결된 자소켓을 닫고 메모리를 해제 하도록 CloseChild()함수를 호출하도록 재정의 해야 합니다.

이제 마지막 작업만을 남겨두고 있습니다.


대화상자 클래스에서 서버 소켓을 초기화 하고 데이터를 전송하는 작업입니다.

CChatServerDlg 클래스의 OnInitDialog() 함수에서 서버 소켓을 초기화 하는 InitServer() 함수를 호출하여 서버 소켓이 클라이언트의 연결 요청을 대기하도록 합니다.

다음으로 Send 버튼을 누를 때 호출되는 메시지 핸들러를 추가한 후 클라이언트로 데이터를 송신하는 SendData() 함수를 호출 하도록 합니다.

이것으로 채팅 서버 프로그램을 완성하였습니다.
이제 클라이언트 프로그램을 만들어 확인하는 일만 남았습니다.

그럼 다음시간에 클라이언트 프로그램을 만들어 간단한 채팅 테스트를 진행하도록 하겠습니다.

감사합니다.


신고


Posted by injunech
2013.07.05 11:28


이번시간에는 소켓을 이용해 간단한 채팅 프로그램을 만들어 보도록 하겠습니다.

먼저 채팅 프로그램의 서버와 클라이언트의 통신 순서를 그림을 통해 알아보도록 하겠습니다.

아래 그림을 봐주세요.

그림에서 보는바와 같이 서버와 클라이언트는 통신을 하게 됩니다.

순서를 간단히 살펴보면 다음과 같습니다.

1. 서버 프로그램에서 서버 소켓이 클라이언트의 접속을 기다립니다.
서버측에서 클라이언트의 접속을 기다리기 위해 소켓을 생성후 Listen() 함수를 실행해 클라이언트가 접속할 때까지 대기 하도록 합니다. 서버 소켓을 생성할 때 다른 응용프로그램과의 구분을 위해 특정 포트를 지정해야 합니다.(여기서는 1470번 포트를 사용하도록 하겠습니다.)

2. 클라이언트 프로그램에서 서버 소켓에 접속을 요청합니다.
서버가 Listen()함수를 실행하여 대기 상태에 있을 때 클라이언트 프로그램에서 Connect() 함수를 호출하면 접속할 수 있습니다.

3. 데이터 송수신
클라이언트가 서버와 접속에 성공하면 서버와 클라이언트는 각각 소켓 객체를 갖게 됩니다. 각각의 소켓은 데이터 송수신을 위해 사용됩니다.

그럼 위와 같은 순서로 동작하게될 채팅 프로그램을 작성해 보도록 하겠습니다.


먼저 서버 프로그램을 만들어 보겠습니다.

채팅 서버는 클라이언트의 요청을 받아줄 소켓과 실제 클라이언트와 통신을 담당할 소켓(자소켓)이 필요합니다.
CSocket의 파생 클래스에 OnAccept() 함수를 재정의 해야 합니다. 클라이언트의 연결 요청이 발생하였을 때 클라이언트와 통신을 담당할 소켓을 생성해 주는 코드를 기술하게 됩니다.
클라이언트와 통신을 담당할 자소켓 클래스 역시 CSocket의 파생 클래스여야 하고 OnReceive() 함수를 재정의 해야 합니다. 이 함수에는 클라이언트에서 데이터를 송신하면 이를 수신하는 코드를 기술하게 됩니다.

먼저 윈도우 소켓을 지원받는 프로젝트 생성을 위해 대화상자 기반으로 MFC 프로젝트를 생성합니다. (프로젝트명은 ChatServer로 하겠습니다.)

아래 그림과 같이 채팅 서버 GUI를 구성합니다.

다음으로 클라이언트의 연결 요청을 기다리며 대기하는 서버 소켓 클래스와 클라이언트와 통신을 담당하게될 자소켓을 CSocket의 파생 클래스로 정의합니다.

아래 그램과 같이 MFC 클래스 마법사를 이용해서 CServerSocket과 CChildSocket 클래스를 CSocket의 파생 클래스로 구현합니다.

다음으로 CChatServerApp 클래스에 클라이언트의 접속을 위해 대기하는 서버 소켓과 통신을 위한 자소켓을 위한 멤버 변수 아래 그림과 같이 선언합니다.

아래와 같이 생성자에 추가한 멤버 변수를 초기화 합니다.

서버 소켓과 자소켓 객체가 어플리케이션 클래스에 생성이 되었습니다.

이제 접속과 데이터 송수신에 필요한 함수를 만들도록 하겠습니다.

필요한 함수는 다음과 같습니다.

void InitServer()

서버 소켓 초기화

void CleanUp()

소켓을 닫고 메모리 해제

void SendData(CString strData)

데이터 송신

void ReceiveData()

데이터 수신

void Accept()

접속 허용

void CloseChild()

자소켓 닫고 메모리 해제

각각의 함수는 아래와 같이 내용을 구현합니다.

함수 구현까지 마쳤습니다.

이제 남은 작업은 데이터 송수신을 위한 가상함수 재정의 부분과 대화상자 클래스에서 서버 소켓을 초기화 하고 데이터를 전송하는 부분입니다.

남은 작업은 다음시간에 계속 이어가도록 하겠습니다.

감사합니다.

이글은 초보 개발자를 위한 비주얼 C++ MFC 입문과 정석용의 TCP/IP 소켓 프로그래밍 책을 참고하여 작성하였습니다.


신고


Posted by injunech
2013.07.05 11:26


서버 프로그램이 준비되었으니 클라이언트 프로그램을 구현하도록 하겠습니다.
클라이언트 프로그램은 ‘연결’ 버튼을 클릭하면 서버 프로그램에 연결하여 서버로부터 전송된 문자열을 화면에 출력하게 됩니다.

MFC로 클라이언트 프로그램을 구현할 때 다음의 순서로 진행하도록 하겠습니다.
1 응용 프로그램 마법사로 프로젝트를 만듭니다.
2 GUI를 설계하고, 각각의 컨트롤에 대해 멤버 함수와 멤버 변수를 추가하고 코딩합니다.
3 서버 프로그램과 연결해서 기능을 검증합니다.

클라이언트 프로그램을 구현하기 위해서 프로젝트를 생성하겠습니다.
대화 상자 기반으로 고급기능에서 ‘Window 소켓’을 체크하여 프로젝트를 생성합니다.
프로젝트 이름은 HelloClient로 하겠습니다.
서버 프로그램과 마찬가지 순서로 프로젝트를 생성합니다.

다음으로 GUI설계와 컨트롤에 대한 멤버 함수와 멤버 변수를 추가하도록 하겠습니다.
GUI를 다음과 같이 구성합니다.

준비가 되었으면 HelloClientDlg.h를 작성하도록 하겠습니다.

다음으로 CHelloClientDlg 클래스에서 연결 버튼을 누르면 수행하는 OnBnClickedButtonConnect 멤버 함수의 내용을 구현하도록 하겠습니다.

프로그램 구현을 모두 끝냈습니다.

이제 모든 준비가 끝났습니다.

준비된 서버 프로그램과 클라이언트 프로그램을 실행하여 잘 동작하는지 확인해 보도록 하겠습니다.

먼저 서버 프로그램을 실행합니다.

서버 프로그램이 실행되면 시작버튼을 눌러 클라이언트의 요청을 기다립니다.

소켓 생성을 성공하면 위와 같이 Socket Create Success 메시지를 출력하고 서버는 클라이언트의 연결 요청을 기다리게 됩니다.

소켓 생성을 실패한 경우 아래와 같이 메시지를 출력하게 됩니다.

서버 준비가 완료되면 클라이언트 프로그램을 실행합니다.

클라이언트 프로그램이 실행되면 연결버튼을 눌러 서버로부터 문자열을 바당 출력하는지 확인합니다.

Hello World를 확인하셨나요?

네트워크 프로그래밍의 세계에 오신걸 환영합니다^^

그럼 다음시간에 만날 수 있길 바라며 이만 줄입니다.



신고


Posted by injunech
2013.07.05 11:25


이제부터 프로그래밍이라는걸 시작해 보도록 하겠습니다.

대부분 프로그래밍의 처음이 그렇듯이 소켓 프로그램도 마찬가지로 간단한 문자열(Hello World)을 네트워크상에서 출력해 보는 것으로 시작하도록 하겠습니다.

일반적으로 소켓 프로그램은 서비스를 요청하는 클라이언트와 클라이언트의 요청을 받아 서비스하는 서버로 구성됩니다.

지금부터 구현할 소켓 프로그램은 클라이언트 프로그램이 네트워크상에서 통신 채널을 통해 서버측에 연결되면 서버 프로그램이 즉시 문자열을 클라이언트측에 전송하고, 클라이언트 프로그램은 전송받은 문자열을 화면에 출력합니다.

그럼 먼저 서버 프로그램을 구현해 보도록 하겠습니다.
서버 프로그램은 시작 버튼 하나와 상태를 알려주는 스태틱 텍스트로 구성되고, 사용자가 시작 버튼을 누르면 서버가 클라이언트와의 연결을 기다리는 ‘Server Start’라는 상태를 알리게 됩니다.

MFC로 서버 프로그램을 구현할 때 다음의 순서로 진행하도록 하겠습니다.

1 응용 프로그램 마법사로 프로젝트를 만듭니다.
2 소켓으로 사용할 CSocket::CListenSocket과 CSocket::CServiceSocket 객체를 생성합니다.
3 GUI를 설계하고, 각각의 컨트롤에 대해 멤버 함수와 멤버 변수를 추가하고 코딩합니다.
4 클라이언트 프로그램과 연결해서 서버로서의 기능을 검증합니다.

서버 프로그램을 구현하기 위해서 먼저 프로젝트를 생성하겠습니다.
대화 상자 기반으로 고급기능에서 ‘Window 소켓’을 체크하여 프로젝트를 생성합니다.
프로젝트 이름은 HelloServer로 하겠습니다.

저는 Visual Studio 2008을 사용하였습니다.

응용 프로그램 종류에서 대화 상자 기반으로 선택합니다.

고급기능에서 Window 소켓 항목을 체크하고 프로젝트를 생성합니다.

다음으로 소켓 객체(CSocket::CListenSocket과 CSocket::CServiceSocket)의 생성하겠습니다.
CListenSocket 객체는 클라이언트로부터의 연결 요청을 받아들이는 역할을 합니다. 이 객체는 클라이언트의 연결 요청을 받으면 OnAccept 메시지 처리기가 실행되어 연결 요청을 처리합니다.

먼저 MFC 클래스 마법사를 이용하여 CSocket 클래스를 기본클래스로 해서 CListenSocket 객체를 생성합니다.


CListenSocket 객체는 HelloServer 프로젝트의 주 대화 상자 객체와 서로 자료나 메시지를 주고 받으면서 작업해야 합니다. 따라서 프로젝트의 이름으로 HelloServer를 사용하기 때문에 주 대화 상자 객체의 이름은 CHelloServerDlg가 됩니다.

CHelloServerDlg 객체의 시작 버튼을 누르면 CListenSocket 객체를 새로 생성하게 됩니다. CListenSocket 객체로 클라이언트로부터의 연결 요청이 오면, OnAccept 메시지 처리기가 실행되지만 OnAccept 메시지 처리기에서 클라이언트의 연결 요청을 처리하지 않고, 이를 대화 상자 CHelloSeverDlg로 객체로 전달해서 처리하게 됩니다. 따라서 CHelloSeverDlg CListenSocket는 서로의 객체에 대한 주소를 주고 받습니다.

CListenSocket.h 파일을 다음과 같이 작성합니다.

소스 설명은 주석으로 대신 하도록 하겠습니다.

헤더 파일의 작성이 끝났습니다.

다음으로 CListenSocket.cpp을 다음과 같이 구현하겠습니다.

CListenSocket에 대한 준비가 끝났습니다.

다음으로 CListenSocket 객체를 이용하여 클라이언트로부터의 연결 요청을 받아들이고 해당 클라이언트에 대한 처리를 수행할 CServiceSocket 객체를 생성합니다.

CServiceSocket 객체 역시 HelloServer 프로젝트의 주 대화 상자인 CHelloServerDlg 객체와 자료를 송수신하기 위해 서로의 객체에 대한 주소를 주고 받습니다.

ServiceSocket.h을 다음과 같이 작성합니다.

ServiceSocket.cpp을 다음과 같이 구현합니다.

다음으로 GUI설계와 컨트롤에 대한 멤버 함수와 멤버 변수를 추가하도록 하겠습니다.
GUI를 다음과 같이 구성합니다.

HelloServer.h를 작성하도록 하겠습니다. 시작 버튼을 누르면 수행하는 OnBnClickedButtonConnect 메소드를 작성합니다.

CHelloServerDlg.cpp을 다음과 같이 구현합니다.

Hello World를 출력하기 위한 서버프로그램의 준비가 끝났습니다.

이제 빨리 클라이언트 프로그램을 만들어 서버 프로그램과 서로 잘 동작하는지 확인는 일만 남았습니다.

클라이언트 프로그램은 다음 시간에~^^;

그럼 오늘은 여기까지 입니다.

수고하셨습니다.

이 글은 열혈강의 Visual C++ 2008 MFC 윈도우 프로그래밍, 정석용의 TCP/IP 소켓 프로 그래밍 책을 참고하여 작성되었습니다.



신고


Posted by injunech
2013.07.05 06:58


제목/목차

1. 소개
2. 클라이언트와 서버간 통신 개요
3. 간단한 서버와 클라이언트 구현
3.1 서버 - 기다리는 소켓 만들기
3.2 클라이언트 - 서버로 연결
3.3 서버 - 클라이언트의 연결 시도 받아들이기
3.4 클라이언트와 서버 - 자료 주고받기
4 만든 클라이언트와 서버를 컴파일하고 테스트
4.1 파일 목록
4.2 컴파일과 테스트
5. 결론

1. 소개

소켓은 프로세스간에 자료를 교환하는 수단이다. 프로세스는 같은 컴퓨터에 있거나 네트웍으로 연결된 서로 다른 컴퓨터에 있을 수 있다. 소켓이 연결되면 한쪽이 연결을 닫을 때까지 양편 모두 자료를 보낼 수 있다.

나는 작업중인 프로젝트에 소켓이 필요해서 소켓 API 함수를 감싸는 C++ 클래스를 개발하고 다듬었다. 일반적으로 자료를 요청하는 프로그램을 클라이언트, 요청에 응답하는 프로그램을 서버라고 한다. 내가 만든 ClientSocket과 ServerSocket, 주된 두 클래스를 사용하여 클라이언트와 서버가 서로 자료를 교환할 수 있다.

이 글의 목표는 프로그램에서 ClientSocket과 ServerSocket 클래스를 사용하는 방법을 알리는 것이다. 먼저 클라이언트와 서버간 통신에대해 간단히 다룬 다음, 이 두 클래스를 사용하여 간단한 서버와 클라이언트 예제를 만들 것이다.

2. 클라이언트와 서버간 통신 개요

코드로 들어가기전에 전형적인 클라이언트와 서버간 연결 단계를 간단히 살펴보자. 다음 표는 단계들을 보여준다.

서버클라이언트
1. 기다리는 소켓(listening socket)을 만들고 클라이언트에서 연결을 기다린다.
2. 클라이언트 소켓을 만들고 서버로 연결을 시도한다.
3. 클라이언트의 연결 시도를 받아들인다.
4. 자료를 주고받는다.4. 자료를 주고받는다.
5. 연결을 닫는다.5. 연결을 닫는다.

기본적으로는 이렇다. 먼저 서버가 기다리는 소켓을 만들고 클라이언트의 연결 시도를 기다린다. 클라이언트가 자체 소켓을 만들고 서버와 연결을 시도한다. 서버는 연결을 받아들이고, 자료 교환이 시작된다. 소켓 연결을 통해 모든 자료가 전달되면 양쪽 중 하나가 연결을 닫는다.

3. 간단한 서버와 클라이언트 구현

이제 코드로 들어갈 시간이다. 이제부터 개요에서 다룬 단계를 모두 수행하는 클라이언트와 서버를 만든다. 우리는 일반적으로 일어나는 순서대로 - 예를 들어 먼저 소켓을 기다리는 서버 부분을 만든 다음 서버로 연결하는 클라이언트 부분을 만드는 등 - 구현한다. 전체 코드는 simple_server_main.cppsimple_client_main.cpp에서 볼 수 있다.

미리 소스코드를 살펴보고 실행해보려면 여기를 읽어봐라. 프로젝트 파일 목록과 어떻게 컴파일하고 테스트하는지를 설명한다.

3.1 서버 - 기다리는 소켓 만들기

첫번째 할 일은 클라이언트에서 들어오는 요청을 기다리는 간단한 서버를 만드는 것이다. 다음은 서버 소켓을 만드는 코드이다.

목록 1 : 서버 소켓 만들기 ( simple_server_main.cpp의 일부 )
#include "ServerSocket.h"
#include "SocketException.h"
#include 

int main ( int argc, int argv[] )
{
  try
    {
      // Create the server socket
      ServerSocket server ( 30000 );

      // rest of code -
      // accept connection, handle request, etc...

    }
  catch ( SocketException& e )
    {
      std::cout << "Exception was caught:" << e.description() << "\nExiting.\n";
    }

  return 0;
}


이것만으로 끝났다. ServerSocket 클래스의 생성자는 기다리는 소켓을 만드는데 필요한 소켓 API를 부른다. 자세한 사항을 감추기때문에 로컬 포트에 기다리기위해 이 클래스 객체를 생성하기만 하면 된다.

try/catch 문을 주목하라. ServerSocket과 ClientSocket 클래스는 C++의 예외처리 기능을 사용한다. 클래스 함수가 어떤 이유에서건 문제가 생기면 SocketException.h에 정의된 SocketException 형의 예외를 발생한다. 이 예외를 처리하지 않으면 프로그램이 끝나기때문에 처리해주는 것이 좋다. 위에서처럼 SocketException의 description() 함수를 사용하여 오류문을 얻을 수 있다.

3.2 클라이언트 - 서버로 연결

전형적인 클라이언트와 서버간 연결의 두번째 단계는 클라이언트가 서버로 연결을 시도하는 일이다. 코드는 방금 전에 본 서버 코드와 비슷하다.

목록 2 : 클라이언트 소켓 만들기 ( simple_client_main.cpp의 일부 )
#include "ClientSocket.h"
#include "SocketException.h"
#include 
#include 

int main ( int argc, int argv[] )
{
  try
    {
      // Create the client socket
      ClientSocket client_socket ( "localhost", 30000 );

      // rest of code -
      // send request, retrieve reply, etc...

    }
  catch ( SocketException& e )
    {
      std::cout << "Exception was caught:" << e.description() << "\n";
    }

  return 0;
}


ClientSocket 클래스 객체를 만들기만하면 리눅스 소켓을 만들어서 생성자에 주어진 호스트와 포트로 연결한다. ServerSocket 클래스와 같이 생성자가 어떤 이유에서건 문제가 생기면 오류가 발생한다.

3.3 서버 - 클라이언트의 연결 시도 받아들이기

클라이언트와 서버간 연결의 다음 단계는 서버에서 일어난다. 서버가 클라이언트의 연결 시도를 받아들이면, 두 소켓 양단간 통신 채널이 열린다.

우리는 간단한 서버에 이 기능을 추가해야 한다. 다음은 수정된 버전이다.

목록 3 : 클라이언트 연결 받아들이기 ( simple_server_main.cpp의 일부 )
#include "ServerSocket.h"
#include "SocketException.h"
#include 

int main ( int argc, int argv[] )
{
  try
    {
      // Create the socket
      ServerSocket server ( 30000 );

      while ( true )
	{
	  ServerSocket new_sock;
	  server.accept ( new_sock );

	  // rest of code -
	  // read request, send reply, etc...

	}
    }
  catch ( SocketException& e )
    {
      std::cout << "Exception was caught:" << e.description() << "\nExiting.\n";
    }

  return 0;
}

연결을 받아들이기위해 accept 함수를 호출하면 된다. 이 함수는 연결 시도를 받아들이고, 연결에 대한 소켓 정보를 new_sock에 채운다. 우리는 다음 절에서 어떻게 new_sock을 사용하는지 볼 것이다.

3.4 클라이언트와 서버 - 자료 주고받기

이제 서버는 클라이언트의 연결 요청을 받아들였고, 소켓 연결을 통해 자료를 주고받을 시간이다.

C++의 고급 기능중 하나가 연산자를 오버로딩하는 - 간단히 말해서, 연산자가 특정 작업을 하도록 만드는 - 능력이다. 나는 ClientSocket과 ServerSocket 클래스의 <<와 >> 연산자를 오버로딩하여, 연산자를 사용하여 소켓에서 자료를 읽고쓸 수 있게 만들었다. 다음은 간단한 서버의 수정된 버전이다.

목록 4 : 간단한 서버 구현 ( simple_server_main.cpp의 일부 )
#include "ServerSocket.h"
#include "SocketException.h"
#include 

int main ( int argc, int argv[] )
{
  try
    {
      // Create the socket
      ServerSocket server ( 30000 );

      while ( true )
	{

	  ServerSocket new_sock;
	  server.accept ( new_sock );

	  try
	    {
	      while ( true )
		{
		  std::string data;
		  new_sock >> data;
		  new_sock << data;
		}
	    }
	  catch ( SocketException& ) {}

	}
    }
  catch ( SocketException& e )
    {
      std::cout << "Exception was caught:" << e.description() << "\nExiting.\n";
    }

  return 0;
}

new_sock 변수는 모든 소켓 정보를 저장하고 있어서, 클라이언트와 자료를 교환하는데 사용한다. "new_sock >> data;" 줄은 "new_sock에서 자료를 읽어서 'data'라는 문자열 변수에 저장한다"는 뜻이다. 비슷하게 다음 줄은 'data'에 있는 자료를 소켓을 통해 클라이언트로 보낸다.

주의를 기울였다면 여기서 만든 것이 echo 서버임을 알 수 있을 것이다. 클라이언트가 보낸 자료는 모두 다시 클라이언트에게 그대로 되돌려진다. 우리는 자료를 보내고 서버의 응답을 출력하는 클라이언트를 작성할 수 있다.

목록 5 : 간단한 클라이언트 구현 ( simple_client_main.cpp의 일부 )
#include "ClientSocket.h"
#include "SocketException.h"
#include 
#include 

int main ( int argc, int argv[] )
{
  try
    {

      ClientSocket client_socket ( "localhost", 30000 );

      std::string reply;
      try
	{
	  client_socket << "Test message.";
	  client_socket >> reply;
	}
      catch ( SocketException& ) {}

      std::cout << "We received this response from the server:\n\"" << reply << "\"\n";;

    }
  catch ( SocketException& e )
    {
      std::cout << "Exception was caught:" << e.description() << "\n";
    }

  return 0;
}

우리는 문자열 "Test Message."를 서버로 보내고, 서버의 응답을 표준출력으로 출력한다.

4. 만든 클라이언트와 서버를 컴파일하고 테스트

우리는 ClientSocket과 ServerSocket 클래스의 기본적인 사용법을 살펴봤다. 이제 프로젝트 전체를 컴파일하여 테스트해보자.

4.1 파일 목록

예제는 아래 파일들로 구성된다.

기타:
Makefile - 이 프로젝트의 Makefile
Socket.h, Socket.cpp - 소켓 API 함수를 구현한 Socket 클래스
SocketException.h - SocketException 클래스
서버:
simple_server_main.cpp - 주파일
ServerSocket.h, ServerSocket.cpp - ServerSocket 클래스
클라이언트:
simple_client_main.cpp - 주파일
ClientSocket.h, ClientSocket.cpp - ClientSocket 클래스

4.2 컴파일과 테스트

컴파일은 간단하다. 먼저 모든 프로젝트 파일을 하위디텍로리에 저장하고, 명령행 프롬프트에 다음과 같이 입력한다.

prompt$ cd directory_you_just_created
prompt$ make

그러면 프로젝트의 모든 파일을 컴파일하여 simple_server와 simple_client 출력 파일을 만든다. 두 출력 파일을 테스트하기위해 한 명령행 프롬프트에서 서버를 실행하고, 다른 명령행 프롬프트에서 클라이언트를 실행한다.

첫번째 프롬프트:
prompt$ ./simple_server
running....



두번째 프롬프트:
prompt$ ./simple_client
We received this response from the server:
"Test message."
prompt$

클라이언트는 서버로 자료를 보내고, 응답을 읽어서 위에서처럼 표준출력으로 출력한다. 클라이언트를 원하는만큼 실행할 수 있다. 서버는 매 요청에 응답한다.

5. 결론

소켓은 프로세스간에 자료를 보내는 간단하고 효율적인 방법이다. 이 글에서 우리는 소켓 통신을 살펴보고 서버와 클라이언트 예제를 만들어봤다. 이제 당신의 프로그램에 소켓 통신을 추가할 수 있다!

신고

'Programming > CPP' 카테고리의 다른 글

멀티바이트와 유니코드  (0) 2013.07.27
BroadCasting 참고 코드  (0) 2013.07.09
Virtual Key Code  (0) 2013.07.06
키보드 이벤트 처리하기  (0) 2013.07.05
Visual Studio 2012 단축키  (0) 2013.07.05
소켓통신  (0) 2013.07.05


Posted by injunech
2013.06.07 17:09


안드로이드 작업을 하다보면 메니페스트 파일에 넣어야하는 User-permission 을 잊거나 생각이

안날경우가 있따. 그래서 일단 적어 놓는다.

</application> 밑에 추가할것 ㅋ

 

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

//위치정보 확인함
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>

//위치정보 확인함

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

//wifi 연결을 확인함
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>

//wifi 체인지를 확인함

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

//네트웍이 연결된것을 확인할수 있게함

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

//부팅완료를 확인할수있게함

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

// 인터넷을 사용함

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

// 외장메모리 사용

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

//녹음이 가능하게 함

 

ACCESS_CHECKIN_PROPERTIES      체크인데이터베이스의_속성테이블로_액세스
ACCESS_COARSE_LOCATION         코스_로케이션_액세스_(Cell-ID/WiFi)
ACCESS_FINE_LOCATION           파인로케이션_액세스(GPS)          
ACCESS_LOCATION_EXTRA_COMMANDS 로케이션_옵션_커맨드_액세스       
ACCESS_MOCK_LOCATION           목_로케이션_프로바이더_생성_(테스트용)
ACCESS_NETWORK_STATE           네트워크_상태_접근                
ACCESS_SURFACE_FLINGER         서피스_플링거_접근                
ACCESS_WIFI_STATE              WiFi상태_접근                     
ADD_SYSTEM_SERVICE             시스템서비스_추가                 
BATTERY_STATS                  배터리_상태                       
BLUETOOTH                      블루투스                          
BLUETOOTH_ADMIN                블루투스_어드민                   
BRICK                          디바이스_실효성_지정              
BROADCAST_PACKAGE_REMOVED      제거된_패키지에_대한_notification_브로드캐스트
BROADCAST_SMS                  SMS에_대한_브로드캐스트           
BROADCAST_STICKY               인텐트_브로드캐스트               
CALL_PHONE                     통화                              
CALL_PRIVILEGED                통화(긴급전화_포함)               
CAMERA                         카메라                            
CHANGE_COMPONENT_ENABLED_STATE 컴포넌트의_실효성_변경            
CHANGE_CONFIGURATION           컨피그_변경                       
CHANGE_NETWORK_STATE           통신상태_변경                     
CHANGE_WIFI_STATE              WiFi상태_변경                     
CLEAR_APP_CACHE                어플리케이션_캐시_클리어          
CLEAR_APP_USER_DATA            어플리케이션의_유저데이터_클리어  
CONTROL_LOCATION_UPDATES       위치정보_갱신                     
DELETE_CACHE_FILES             캐시파일_제거                     
DELETE_PACKAGES                패키지_제거                       
DEVICE_POWER                   전원상태에_대한_로우레벨_접근     
DIAGNOSTIC                     진단리소스_읽고쓰기               
DISABLE_KEYGUARD               키_가드_끄기_DUMP_덤?            
EXPAND_STATUS_BAR              상태표시줄_확장                   
FACTORY_TEST                   팩토리_테스트                     
FLASHLIGHT                     플래시라이트                      
FORCE_BACK                     포스백                            
GET_ACCOUNTS                   어카운트_획득                     
GET_PACKAGE_SIZE               패키지_획득                       
GET_TASKS                      태스크_획득                       
HARDWARE_TEST                  하드웨어테스트                    
INJECT_EVENTS                  유저이벤트_키/트랙볼              
INSTALL_PACKAGES               패키지_인스톨                     
INTERNAL_SYSTEM_WINDOW         내부_시스템윈도_활용              
INTERNET                       인터넷                            
MANAGE_APP_TOKENS              어플리케이션_토큰관리             
MASTER_CLEAR                   마스터_클리어                     
MODIFY_AUDIO_SETTINGS          오디오설정_편집                   
MODIFY_PHONE_STATE             전화상태_편집                     
MOUNT_UNMOUNT_FILESYSTEMS      파일시스템_편집                   
PERSISTENT_ACTIVITY            액티비티_지속                     
PROCESS_OUTGOING_CALLS         전화_발신처리_접근                
READ_CALENDAR                  캘린더_읽어오기                   
READ_CONTACTS                  주소록_읽어오기                   
READ_FRAME_BUFFER              프레임버퍼_읽어오기               
READ_INPUT_STATE               입력상태_읽어오기                 
READ_LOGS                      로그_읽어오기                     
READ_OWNER_DATA                owner_data읽어오기                
READ_PHONE_STATE               통화상태_읽어오기_READ_SMS_SMS읽어오기
READ_SYNC_SETTINGS             동기설정_읽어오기                 
READ_SYNC_STATS                동기상태_읽어오기                 
REBOOT                         reboot                            
RECEIVE_BOOT_COMPLETED         boot완료                          
RECEIVE_MMS                    MMS수신                           
RECEIVE_SMS                    SMS수신                           
RECEIVE_WAP_PUSH               WAP수신                           
RECORD_AUDIO                   오디오_수신                       
REORDER_TASKS                  태스크_Z오더                      
RESTART_PACKAGES               패키지_리스타트                   
SEND_SMS                       SMS송신                           
SET_ACTIVITY_WATCHER           액티비티_왓쳐지정                 
SET_ALWAYS_FINISH              액티비티_전체_종료                
SET_ANIMATION_SCALE            스케일_애니메이션_지정            
SET_DEBUG_APP                  디버그어플리케이션_지정           
SET_ORIENTATION                스크린_로테이션지정               
SET_PREFERRED_APPLICATIONS     자주_사용하는_어플리케이션_지정   
SET_PROCESS_FOREGROUND         포어그라운드_처리지정             
SET_PROCESS_LIMIT              제한처리_지정                     
SET_TIME_ZONE                  타임존_지정                       
SET_WALLPAPER                  배경화면_지정                     
SET_WALLPAPER_HINTS            배경화면_힌트_지정                
SIGNAL_PERSISTENT_PROCESSES    지속처리_시그널_지정              
STATUS_BAR                     상태표시줄_지정                   
SUBSCRIBED_FEEDS_READ          서브스트립드_피즈_읽어오기        
SUBSCRIBED_FEEDS_WRITE         서브스트립드_피즈_쓰기            
SYSTEM_ALERT_WINDOW            알림_윈도우                       
VIBRATE                        진동                              
WAKE_LOCK                      알람                              
WRITE_APN_SETTINGS             APN설정_쓰기                      
WRITE_CALENDAR                 캘린더_쓰기                       
WRITE_CONTACTS                 주소록_쓰기                       
WRITE_GSERVICES                G서비스_쓰기                      
WRITE_OWNER_DATA               owner_data쓰기                    
WRITE_SETTINGS                 설정_쓰기
WRITE_SMS                      SMS쓰기 
WRITE_SYNC_SETTINGS            동기설정_쓰기

신고


Posted by injunech
2013.05.31 11:28


FROM drawable TO bitmap :

Drawable d = ImagesArrayList.get(0);  
Bitmap bitmap = ((BitmapDrawable)d).getBitmap();

 

FROM resource id of drawable TO bitmap:

Bitmap b1 = BitmapFactory.decodeResource(context.getResources(),R.drawable.icon_resource);

 

Reference:

http://stackoverflow.com/questions/3035692/how-to-convert-a-drawable-to-a-bitmap

신고

'Programming > Android' 카테고리의 다른 글

Android Bitmap Utility(resize, crop) 클래스..  (0) 2013.07.25
android uses-permission  (0) 2013.06.07
Convert drawable to bitmap  (0) 2013.05.31
안드로이드 디렉토리 생성 및 파일 I/O  (0) 2013.05.29
Android WebView 예제  (0) 2013.05.27
Bitmap Merge  (0) 2013.05.26


Posted by injunech
2013.05.29 10:51


보안상의 이유로 응용 프로그램은 허가받은 위치에만 파일 생성 가능.. 이 제한을 일일이 준수하기 어려우므로 
보안이 적용된 파일 관리 메서드를 별도로 제공..

FileOutputStream openFileOutput(String name, int mode)
FileInputStream openFileInput(String name)

 MODE_PRIVATE 혼자만 사용하는 배타적인 모드로 파일 생성 .. (디폴트)
 MODE_APPEND 파일이 이미 존재할 경우 덮어쓰기 모드로 열지 않고 추가 모드로 연다. ( 기존 내용에 추가 )
 MODE_WORLD_READABLE 다른 응용 프로그램이 읽을 수 있도록 허용
 MODE_WORLD_WRITEABLE 다른 응용 프로그램이 쓸 수 있도록 허용

// 파일 저장

FileOutputStreamfos = openFileOutput("text.txt", Context.MODE_WORLD_READABLE);


String str = mEdit.getText().toString();


                                

fos.write(str.getBytes());


fos.close();


mEdit.setText("Write Success");



파일 경로 : /data/data/패키지명/files/ 디렉토리 .. 


- 직접적으로 확인은 불가하다 .. ( Root Explorer(App) 이용해서 확인 .. 루트 권한 필요 )


// 파일 읽기

FileInputStream fis = openFileInput("text.txt");


byte[] data = new byte[fis.available()];


while(fis.read(data) != -1){}


fis.close();


mEdit.setText(new String(data));



*SD Card 이용 I/O

기본 java I/O 와 동일 


// 파일 저장

String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();


File dir = new File(sdPath,  "testing");


dir.mkdir();


File file = new File(dir, "file.txt");


FileOutputStream fos = new FileOutputStream(file);


String str = mEdit.getText().toString();


fos.write(str.getBytes());


fos.close();


mEdit.setText("write success");






// 파일 읽기

String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();

FileInputStream fis = new FileInputStream(sdPath + "/testing/file.txt");

byte[] data = new byte[fis.available()];

while(fis.read(data)!=-1){}

fis.close();

mEdit.setText(new String(data));



※ SD Card 디렉토리 생성시 에러상황 .. 해결법 ..


위와 같이 코드를 이용해 디렉토리 생성시 에러가 발생 할 경우 아래의 내용을 추가해야한다.. 


AndroidManifest.xml 


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


SD card의 파일을 엑세스 하려면 Manifest에 퍼미션을 지정해야한다.


※ SD Card 관련 정보 보기


1. Environment.getExternalStorageState()

SD card 현재 상태 .. mounted : 읽고 쓰기 가능한 상태 .. unmounted : 불가능 상태

2. Environment.getExternalStorageDirectory().getAbsolutePath()

SD card 가 마운트된 경로 .. 

3. Environment.getRootDirectory().getAbsolutePath()

4. Environment.getDataDirectory().getAbsolutePath()

5. Environment.getDownloadCacheDirectory().getAbsolutePath() 

신고


Posted by injunech
2013.05.29 02:17


클래스 java.io.File

java.lang.Object
   |
   +----java.io.File

public class File
extends Object
implements Serializable

이 클래스의 인스턴스는 호스트 파일 시스템의 파일명 또는 디렉토리를 나타냅니다. 파일은 경로명으로 지정되며, 경로명은 절대 경로명 또는 현재 작업 디렉토리에 상대적인 경로명일 수 있습니다. 경로명은 호스트 플랫폼의 명명 규칙을 따라야 합니다.

File 클래스는 기계와 무관한 방식의 파일 및 경로명에 대한 대부분의 기계 종속적인 복잡성을 처리하는 추상 개념을 제공합니다.

파일명 또는 경로가 사용될 때마다, 호스트의 파일 명명 규칙이 사용된다고 가정합니다.


변수 색인

pathSeparator
시스템 종속 경로 분리자 문자열
pathSeparatorChar
시스템 종속 경로 분리자
separator
시스템 종속 경로 분리자
separatorChar
시스템 종속 경로 분리자 문자열

생성자 색인

File(File, String)
지정된 디렉토리에 지정된 이름으로 파일을 나타내는 File 인스턴스를 작성합니다.
File(String)
파일명이 주어진 경로 인수인 파일을 나타내는 File 인스턴스를 작성합니다.
File(String, String)
경로명이 지정된 디렉토리, 분리자 및 name 인수로 구성된 File 인스턴스를 작성합니다.

메소드 색인

canRead()
응용프로그램이 지정된 파일에서 읽을 수 있는지 여부를 테스트합니다.
canWrite()
응용프로그램이 파일에 기록할 수 있는지 여부를 테스트합니다.
delete()
객체가 지정하는 파일을 삭제합니다.
equals(Object)
객체를 지정된 객체와 비교합니다.
exists()
File이 있는지 여부를 테스트합니다.
getAbsolutePath()
객체가 나타내는 파일의 절대 경로명을 리턴합니다.
getCanonicalPath()
File 객체의 경로명에 대한 표준 양식을 리턴합니다.
getName()
객체가 나타내는 파일의 이름을 리턴합니다.
getParent()
File 객체 경로명의 상위 파트를 리턴하거나, 이름에 상위 파트가 없는 경우 null을 리턴합니다.
getPath()
객체가 나타내는 파일의 경로명을 리턴합니다.
hashCode()
파일에 대한 해시 코드를 계산합니다.
isAbsolute()
File 객체가 나타내는 파일이 절대 경로명인지 여부를 테스트합니다.
isDirectory()
File 객체가 나타내는 파일이 디렉토리인지 여부를 테스트합니다.
isFile()
File 객체가 나타내는 파일이 "보통" 파일인지 여부를 테스트합니다.
lastModified()
File 객체가 나타내는 파일이 마지막으로 수정된 시간을 리턴합니다.
length()
File 객체가 나타내는 파일의 길이를 리턴합니다.
list()
File 객체가 지정하는 디렉토리 내의 파일의 목록을 리턴합니다.
list(FilenameFilter)
지정된 필터를 만족시키는 File이 지정하는 디렉토리 내의 파일의 목록을 리턴합니다.
mkdir()
File 객체가 경로명을 지정하는 디렉토리를 작성합니다.
mkdirs()
필요한 상위 디렉토리를 포함하여 File 객체가 경로명을 지정하는 디렉토리를 작성합니다.
renameTo(File)
File 인수가 제공하는 경로명을 갖도록 File 객체가 지정한 파일을 다른 이름으로 변경합니다.
toString()
객체의 문자열 표현을 리턴합니다.

변수

separator
 public static final String separator
시스템 종속 경로 분리자. 이 필드는 시스템 특성 file.separator의 값을 포함하도록 초기화됩니다.

참조:
getProperty
separatorChar
 public static final char separatorChar
시스템 종속 경로 분리자 문자열. 이 필드는 시스템 특성 file.separator값의 첫번째 문자를 포함하도록 초기화됩니다. 이 문자는 디렉토리와 파일명의 파일 컴포넌트를 분리합니다.

참조:
getProperty
pathSeparator
 public static final String pathSeparator
시스템 종속 경로 분리자 문자열. 이 필드는 시스템 특성 file.separator값을 포함하도록 초기화됩니다.

참조:
getProperty
pathSeparatorChar
 public static final char pathSeparatorChar
시스템 종속 경로 분리자. 이 필드는 시스템 특성 file.separator값의 첫번째 문자를 포함하도록 초기화됩니다. 이 문자는 자주 "경로 목록"으로 제공되는 파일 순서에서 파일명을 분리하는 데 사용됩니다.

참조:
getProperty

생성자

File
 public File(String path)
파일명이 주어진 경로 인수인 파일을 나타내는 File 인스턴스를 작성합니다.

매개변수:
path - 파일 경로명
오류: NullPointerException
파일 경로가 null인 경우
참조:
getPath
File
 public File(String path,
             String name)
경로명이 지정된 디렉토리, 분리자 및 name 인수로 구성된 File 인스턴스를 작성합니다.

매개변수:
path - 디렉토리 경로명
name - 파일 경로명
참조:
getPathseparator
File
 public File(File dir,
             String name)
지정된 디렉토리에 지정된 이름으로 파일을 나타내는 File 인스턴스를 작성합니다.

디렉토리 인수가 null인 경우, 결과 File 인스턴스는 경로명이 name 인수인 (시스템 종속) 현재 디렉토리 내의 파일을 나타냅니다. 그렇지 않으면 File 인스턴스는 경로명이 디렉토리의 경로명, 분리자, name 인수인 파일을 나타냅니다.

매개변수:
dir - 디렉토리
name - 파일 경로명
참조:
getPathseparator

메소드

getName
 public String getName()
객체가 나타내는 파일의 이름을 리턴합니다. 이 이름은 마지막 분리자 발생 후의 경로명입니다.

결과:
File 객체로 표현되는 파일의 이름(디렉토리 컴포넌트 없음)
참조:
getPathseparator
getPath
 public String getPath()
객체가 나타내는 파일의 경로명을 리턴합니다.

결과:
File 객체가 나타내는 경로명
getAbsolutePath
 public String getAbsolutePath()
객체가 나타내는 파일의 절대 경로명을 리턴합니다. 이 객체가 절대 경로명을 나타내는 경우, 절대 경로명을 리턴합니다. 그렇지 않으면 현재 사용자 디렉토리, 분리자 및 파일 객체의 경로명을 결합한 경로명을 리턴합니다.

시스템 특성 user.dir에는 현재 사용자 디렉토리가 포함됩니다.

결과:
File에 대한 시스템 종속 절대 경로명
참조:
getPathisAbsolutegetProperty
getCanonicalPath
 public String getCanonicalPath() throws IOException
File 객체의 경로명에 대한 표준 양식을 리턴합니다. 표준 양식의 정확한 정의는 시스템 종속적이나, 보통 현재 사용자 디렉토리에 대한 모든 상대적 참조가 완전하게 분석되는 절대 경로명을 지정합니다. 없는 파일 경로명의 표준 양식은 정의할 수 없는 경우도 있습니다.

오류: IOException
표준 경로의 구성시 파일 시스템 조회가 필요할 수 있기 때문에 I/O 오류가 발생하는 경우
getParent
 public String getParent()
File 객체 경로명의 상위 파트를 리턴하거나, 이름에 상위 파트가 없는 경우 null을 리턴합니다. 상위 파트는 일반적으로 정확한 정의가 시스템 종속적인 경우에도 분리자의 최종 발생을 가져오는 모든 것입니다. UNIX의 경우, 예를 들어 "/usr/lib"의 상위 파트는 "/usr"이고, 해당 상위 파트는 상위가 없는"/"입니다. Windows 플랫폼의 경우, "c:\java"의 상위 파트는 상위가 없는 "c:\"입니다.

참조:
getPathgetCanonicalPathseparator
exists
 public boolean exists()
File이 있는지 여부를 테스트합니다.

결과:
객체가 지정하는 파일이 있는 경우 true, 그렇지 않으면 false
오류: SecurityException
보안 관리 프로그램이 있는 경우, 응용프로그램이 해당 파일에 읽기 액세스할 수 있는지를 보기 위해 File의 경로명으로 checkRead 메소드가 호출됨
참조:
getPathcheckRead
canWrite
 public boolean canWrite()
응용프로그램이 파일에 기록할 수 있는지 여부를 테스트합니다.

결과:
응용프로그램이 객체에 의해 이름이 지정된 파일에 기록할 수 있는 경우 true, 그렇지 않으면 false
오류: SecurityException
보안 관리 프로그램이 있는 경우, 응용프로그램이 해당 파일에 쓰기 액세스할 수 있는지를 보기 위해 File의 경로명으로 checkWrite 메소드가 호출됨
참조:
getPathcheckWrite
canRead
 public boolean canRead()
응용프로그램이 지정된 파일에서 읽을 수 있는지 여부를 테스트합니다.

결과:
객체가 지정하는 파일이 있고 응용프로그램이 파일을 읽을 수 있는 경우 true, 그렇지 않으면 false
오류: SecurityException
보안 관리 프로그램이 있는 경우, 응용프로그램이 해당 파일에 읽기 액세스할 수 있는지를 보기 위해 File의 경로명으로 checkRead 메소드가 호출됨
참조:
getPathcheckRead
isFile
 public boolean isFile()
File 객체가 나타내는 파일이 "보통" 파일인지 여부를 테스트합니다.

파일은 디렉토리가 아니고 다른 시스템 종속 기준을 만족시키는 경우 "보통" 파일입니다. Java 응용프로그램이 작성한 디렉토리가 아닌 파일은 보통 파일입니다.

결과:
객체가 지정하는 파일이 있고 파일이 "보통" 파일인 경우 true, 그렇지 않으면 false
오류: SecurityException
보안 관리 프로그램이 있는 경우, 응용프로그램이 해당 파일에 읽기 액세스할 수 있는지를 보기 위해 File의 경로명으로 checkRead 메소드가 호출됨
참조:
getPathcheckRead
isDirectory
 public boolean isDirectory()
File 객체가 나타내는 파일이 디렉토리인지 여부를 테스트합니다.

결과:
File이 있고 디렉토리인 경우 true, 그렇지 않으면 false
오류: SecurityException
보안 관리 프로그램이 있는 경우, 응용프로그램이 해당 파일에 읽기 액세스할 수 있는지를 보기 위해 File의 경로명으로 checkRead 메소드가 호출됨
참조:
getPathcheckRead
isAbsolute
 public native boolean isAbsolute()
File 객체가 나타내는 파일이 절대 경로명인지 여부를 테스트합니다. 절대 경로명의 정의는 시스템 종속적입니다. 예를 들어, UNIX에서 첫번째 문자가 분리자인 경우 절대 경로명입니다. Windows 플랫폼에서는 첫번째 문자가 ASCII '\' 또는 '/'이거나 콜론이 뒤에 오는 문자로 시작되는 경우 절대 경로명입니다.

결과:
File 객체가 나타내는 경로명이 절대 경로명인 경우 true, 그렇지 않으면 false
참조:
getPathseparator
lastModified
 public long lastModified()
File 객체가 나타내는 파일이 마지막으로 수정된 시간을 리턴합니다.

리턴값은 시스템 종속적이며 최종 수정으로 리턴된 다른 값과 비교하는 데에만 사용되어야 합니다. 절대 시간으로 해석되어서는 안 됩니다.

결과:
객체가 지정한 파일이 최종 수정된 시간, 또는 지정된 파일이 없는 경우 0L
오류: SecurityException
보안 관리 프로그램이 있는 경우, 응용프로그램이 해당 파일에 읽기 액세스할 수 있는지를 보기 위해 File의 경로명으로 checkRead 메소드가 호출됨
참조:
getPathcheckRead
length
 public long length()
File 객체가 나타내는 파일의 길이를 리턴합니다.

결과:
객체가 지정한 파일의 길이(바이트 단위), 또는 지정된 파일이 없는 경우 0L
오류: SecurityException
보안 관리 프로그램이 있는 경우, 응용프로그램이 해당 파일에 읽기 액세스할 수 있는지를 보기 위해 File의 경로명으로 checkRead 메소드가 호출됨
참조:
getPathcheckRead
mkdir
 public boolean mkdir()
File 객체가 경로명을 지정하는 디렉토리를 작성합니다.

결과:
디렉토리를 작성할 수 있는 경우 true, 그렇지 않으면 false
오류: SecurityException
보안 관리 프로그램이 있는 경우, 응용프로그램이 해당 파일에 쓰기 액세스할 수 있는지를 보기 위해 File의 경로명으로 checkWrite 메소드가 호출됨
참조:
getPathcheckWrite
renameTo
 public boolean renameTo(File dest)
File 인수가 제공하는 경로명을 갖도록 File 객체가 지정한 파일을 다른 이름으로 변경합니다.

매개변수:
dest - 새로운 파일명
결과:
다른 이름으로 변경한 경우 true, 그렇지 않으면 false
오류: SecurityException
보안 관리 프로그램이 있는 경우, checkWrite 메소드를 파일 객체의 경로명과 목적지 목표 객체의 경로명으로 호출하여 응용프로그램이 두 파일 모두에 기록할 수 있는지를 알아봄
참조:
getPathcheckWrite
mkdirs
 public boolean mkdirs()
필요한 상위 디렉토리를 포함하여 File 객체가 경로명을 지정하는 디렉토리를 작성합니다.

결과:
디렉토리(들)를 작성할 수 있는 경우 true, 그렇지 않으면 false
오류: SecurityException
보안 관리 프로그램이 있는 경우, 디렉토리를 작성하기 전에 작성될 디렉토리 각각의 경로명으로 checkWrite 메소드가 호출됨
참조:
getPathcheckWrite
list
 public String[] list()
File 객체가 지정하는 디렉토리 내의 파일의 목록을 리턴합니다.

결과:
지정된 디렉토리 내의 파일명 배열. 이 목록에는 현재 디렉토리 또는 상위 디렉토리(Unix 시스템에서 "." 및 "..")가 포함되지 않습니다.
오류: SecurityException
보안 관리 프로그램이 있는 경우, 응용프로그램이 해당 파일에 읽기 액세스할 수 있는지를 보기 위해 File의 경로명으로 checkRead 메소드가 호출됨
참조:
getPathcheckRead
list
 public String[] list(FilenameFilter filter)
지정된 필터를 만족시키는 File이 지정하는 디렉토리 내의 파일의 목록을 리턴합니다.

매개변수:
filter - 필터 파일명
결과:
지정된 디렉토리 내의 파일명 배열. 이 목록에는 현재 디렉토리 또는 상위 디렉토리(Unix 시스템에서 "." 및 "..")가 포함되지 않습니다.
오류: SecurityException
보안 관리 프로그램이 있는 경우, 응용프로그램이 해당 파일에 읽기 액세스할 수 있는지를 보기 위해 File의 경로명으로 checkRead 메소드가 호출됨
참조:
getPathFilenameFiltercheckRead
delete
 public boolean delete()
객체가 지정하는 파일을 삭제합니다. 삭제될 목표 파일이 디렉토리인 경우, 삭제를 위해 비워야 합니다.

결과:
파일이 삭제되는 경우 true, 그렇지 않으면 false
오류: SecurityException
보안 관리 프로그램이 있는 경우, 응용프로그램이 해당 파일을 삭제할 수 있는지를 보기 위해 File의 경로명으로 checkDelete 메소드가 호출됨
참조:
getPathcheckDelete
hashCode
 public int hashCode()
파일에 대한 해시 코드를 계산합니다.

결과:
File 객체에 대한 해시 코드값
대체:
Object 클래스에 있는 hashCode
equals
 public boolean equals(Object obj)
객체를 지정된 객체와 비교합니다. 인수가 null이 아니고 경로명이 객체의 경로명인 경우 File이라면, true를 리턴합니다.

매개변수:
obj - 비교할 객체
결과:
객체가 동일한 경우 true, 그렇지 않으면 false
대체:
Object 클래스에 있는 equals
toString
 public String toString()
객체의 문자열 표현을 리턴합니다.

결과:
객체의 경로명을 제공하는 문자열
대체:
Object 클래스에 있는 toString
참조:
getPath

신고

'Programming > JAVA' 카테고리의 다른 글

JNA (Java Native Access)  (0) 2015.03.14
[JAVA] 자바 실행파일 만들기  (0) 2015.03.01
JGoodies JAVA Swing API  (0) 2015.02.07
클래스 java.io.File  (0) 2013.05.29
평년/윤년 구하기  (0) 2013.03.02
날짜  (0) 2013.03.02


Posted by injunech
2013.05.27 15:33


Android WebView예제를 작성해보았습니다. 이전에 작성했던 Fragment 예제에 추가되어있던 WebView인데 해당 글에서 설명을 하지 않아 따로 작성합니다. Fragment를 상속받을때와는 다르게 Activity를 상속받아 작성하였습니다. 사용된 예제는 주소 입력창과 Go 버튼을 추가하여 작성하였습니다.


사용한 API

 WebViewClient API

  http://developer.android.com/reference/android/webkit/WebViewClient.html

 사용한 상속 Public Method

 boolean

 shouldOverrideUrlLoading(WebView view, String url)
  - URL에 따른 페이지 Loding

 void

 onPageFinished(WebView view, String url)
  - 페이지 Loding이 완료되면 알려주는 Method


 WebChromeClient API

  http://developer.android.com/reference/android/webkit/WebChromeClient.html

 void

 onProgressChanged(WebView view, int newProgress)
  - 페이지의 현재 진행사항을 알려줍니다. (Loding 


 WebViewClient API는 기본적인 WebView의 화면을 보여주기 위해서 상속받아 작성하였고, WebChromeClient는 현재 페이지를 Loding하고, Finished 될 때 ProgressBar를 처리하기 위해서 상속받아 사용하였습니다.


예제 코드

Activity - WebView를 처리하는 코드입니다.

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package net.thdev.webviewexample;
 
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
 
@SuppressLint({ "SetJavaScriptEnabled", "NewApi" })
public class WebViewActivity extends Activity {
    private String mInputUrl = "http://www.google.com";
     
    private EditText mEditText;
    private WebView mWebView;
    private WebSettings mWebSettings;
    private ProgressBar mProgressBar;
    private InputMethodManager mInputMethodManager;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_webview);
         
        mEditText = (EditText)findViewById(R.id.edit_Url);
        mWebView = (WebView)findViewById(R.id.webview);
        mProgressBar = (ProgressBar)findViewById(R.id.progressBar);
        findViewById(R.id.btn_go).setOnClickListener(onClickListener);
         
        mInputMethodManager = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
         
        mWebView.setWebChromeClient(new webViewChrome());
        mWebView.setWebViewClient(new webViewClient());
        mWebSettings = mWebView.getSettings();
        mWebSettings.setBuiltInZoomControls(true);
         
        mWebView.loadUrl(mInputUrl);
        mEditText.setHint(mInputUrl);
    }
     
    //Button Event를 처리
    View.OnClickListener onClickListener = new View.OnClickListener() {
         
        @Override
        public void onClick(View v) {
            switch(v.getId()) {
            case R.id.btn_go:
                //InputMethodManager를 이용하여 키보드를 숨김
                mInputMethodManager.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
                mInputUrl = httpInputCheck(mEditText.getText().toString());
                 
                if(mInputUrl == null) break;
                 
                //페이지를 불러온다
                mWebView.loadUrl(mInputUrl);
                mEditText.setText("");
                mEditText.setHint(mInputUrl);
                break;
            }
        }
    };
     
    class webViewChrome extends WebChromeClient {
         
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            //현제 페이지 진행사항을 ProgressBar를 통해 알린다.
            if(newProgress < 100) {
                mProgressBar.setProgress(newProgress);
            } else {
                mProgressBar.setVisibility(View.INVISIBLE);
                mProgressBar.setLayoutParams(new LinearLayout.LayoutParams(0, 0));
            }
        }
    }
     
    class webViewClient extends WebViewClient {
         
        //Loading이 시작되면 ProgressBar처리를 한다.
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            mProgressBar.setVisibility(View.VISIBLE);
            mProgressBar.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 15));
            view.loadUrl(url);
            return true;
        }
         
        @Override
        public void onPageFinished(WebView view, String url) {
            mWebSettings.setJavaScriptEnabled(true);
            mEditText.setHint(url);
            super.onPageFinished(view, url);
        }
    }
     
    //http://를 체크하여 추가한다.
    private String httpInputCheck(String url) {
        if(url.isEmpty()) return null;
         
        if(url.indexOf("http://") == ("http://").length()) return url;
        else return "http://" + url;
    }
}

XML - WebView XML 예제코드입니다.

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
42
43
44
45
46
47
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
 
        <EditText
            android:id="@+id/edit_Url"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:inputType="textUri"
            android:layout_weight="1"
            android:singleLine="true"
            android:hint="" />
 
        <Button
            android:id="@+id/btn_go"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="0"
            android:text="@string/btn_go"
            />
    </LinearLayout>
     
    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:max="100"
        android:progress="0"
        android:secondaryProgress="1"
        android:visibility="invisible"
        style="?android:attr/progressBarStyleHorizontal"
        />
         
    <WebView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/webview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
         
    </WebView>
</LinearLayout>

추가한 Permission

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

결과 화면

 간단하게 작성한 WebView입니다. 진행사항을 표시하기 위해서 WebViewChromeClient를 상속 받아 처리하였습니다. 잠시 보여지고 숨겨지는 간단한 ProgressBar를 추하였습니다. ActionBar를 사용해도 가능하지만 3.0 미만의 별도의 처리를 해야하기에 여기서는 제외시켰습니다. 다음에 ActionBar 예제를 다뤄보겠습니다. 이상 WebView 예제를 마치겠습니다.


다운로드

 다운로드는 예전에 작성해둔 Fragment의 Swipe 예제를 링크하겠습니다. 그 때 작성한 예제코드와 지금의 예제코드가 동일합니다. 아리 링크를 통해 다운로드 가능합니다.

  http://db.tt/dGZ5ckDq

신고


Posted by injunech

티스토리 툴바