[아두이노] [강좌] 49. 와이파이 통신 (3) - WebClient 예제

이번 강좌에서는 WiFly 제조사에서 제공하는 예제 소스 중 WebClient 예제에 대해 알아보자. 



moon_and_james-5 

아무렇지도 않게 다시 시작하기




네트워크를 사용하기 위해서는 그 네트워크를 사용하기 위한 방법을 선택해야 하는데, WiFly 예제에서는 두 가지 방법의 예제를 제공한다. Server/Client 방식과 Pachube 방식. Pachube 방식은 요즘 급격히 떠오르고 있는 사물 인터넷(IOT : Internet Of Tings)을 위한 방식인데, 트렌드를 맞추기 위해 넣었나벼. 나중에 써봐야지.


우선은 Server/Client 방식. 말 그대로 서버(Server)가 있고 클라이언트(Client)가 있는 방식이다. 쉽게 말하자면, 서버는 클라이언트에 제공하기 위한 정보들을 저장하고 있고, 클라이언트는 그 정보가 필요할 때마다 서버에 요청하여 데이터를 전달받는다. 


웹 서비스는 서비스를 제공하는 서버와 서비스를 요청하는 클라이언트로 구성된 Server/Client 방식을 사용한다. 동시에 여러 개의 클라이언트가 서버에 접근할 수 있다는 장점 때문이다. 



자세한 내용은 나보다 네이버가 더 잘 알고 있을테니 네이버를 이용하세용.




근데 예제 소스 설명하려면 진행 과정을 알아야 해. ㅜㅜ 간단하게 살펴보자, 휘리릭!




우리가 구글에 접속하는 경우를 생각해보자. 우리는 단순히 PC 또는 스마트폰 등의 기기에서 Internet Explorer 또는 Chrome(크롬) 등의 웹 브라우저를 실행한 후 주소창에 "www.google.com"을 입력할 것이다. 그럼 구글의 메인 화면이 나오고. 


이 때 Internet Explorer나 Chrome 등의 웹 브라우져는 클라이언트가 되고, 구글(정확히 말하면 구글이 운영하고 있는 서버)은 서버가 된다. 


이 과정을 Server/Client 방식에 기초하여 자세히 살펴보면 다음과 같다. 




① 웹 브라우저를 실행한 후 구글의 주소(URL)을 입력하면 클라이언트인 웹 브라우저가 "www.google.com"이라는 이름의 서버인 구글의 웹 서버로 연결을 요청한다.


② 구글의 웹 서버는 클라이언트가 접속하기를 기다리고 있다가 연결 요청이 오면 연결을 수락한 후 데이터를 주고 받기 위한 길을 만든다.


③ 연결 요청이 수락되면 클라이언트는 서버에게 필요한 데이터를 요청한다. 웹 브라우저가 필요한 데이터는 사용자에게 보여 줄 화면의 데이터 같은 것들. 


④ 웹 서버는 클라이언트(웹 브라우저)로부터 요청 받은 데이터를 클라이언트로 전송한다. 


⑤ 클라이언트인 웹 브라우저는 데이터 수신이 완료되면 서버와의 연결을 해제한다. 


⑥ 그리고 수신된 데이터를 해석하여 웹 브라우저에 화면을 출력한다. 




그럼 다음과 같은 화면이 뚜둥!


6b6f2ee1573f843ea33b4565772f8b0f.png


만일 마우스나 키보드 등의 입력으로 화면을 다시 출력해야 한다면 다시 위 과정을 반복한다. 요청하고, 수신되는 데이터의 종류가 달라질 뿐. 



자, 위 과정을 기억하면서 예제 소스를 열어보자. 스케치 툴의 '파일→예제→SparkFun WiFly Shield→WiFly_WebClient'.


3a8b3b993ab84dd6b6c28fa6b6882f68.png



혹시 '예제' 탭에 'SparkFun WiFly Shield' 탭이 보이지 않는다면 라이브러리 설치 여부를 확인하자. 라이브러리 설치 방법은 이전 강좌를 참조. 




소스를 살펴볼까나. 



소스를 열면 두 개의 탭이 보일 것이다. 

9d7683ca23af2578c3e2055e9d98eb50.png 




예전에 부저 실습 때 한 번 나왔던 거 같은데, 스케치 파일(.ino)과 동일한 위치에 읽기 가능한 파일이 있을 경우 탭이 추가되어 나타난다. "WIFly_WebClient.ino" 파일과 같은 위치에 "Credentials.h" 파일이 존재한다는 것. 


"Credentials.h" 탭을 클릭해보자. 



 

Credentials.h


#ifndef __CREDENTIALS_H__

#define __CREDENTIALS_H__


// Wifi parameters

char passphrase[] = "passphrase";

char ssid[] = "ssid";


#endif


 



와이파이 모듈이 AP에 접속하기 위해 필요한 SSID와 패스워드를 저장하고 있다. 빨간 색으로 표시된 부분을 자신이 접속할 AP의 SSID와 패스워드로 수정해주면 된다. 우리 집 AP의 SSID와 패스워드를 넣어준 소스 코드이다. 



 

char passphrase[] = "0000001726";

char ssid[] = "olleh_WiFi_18B6";


 



유의해야 할 점은 대소문자를 정확히 구분해서 써줘야 한다는 것. 



그리고 다시 "WiFly_WebClient.ino" 탭으로 돌아오자. 



 

WiFly_WebClient.ino


#include <SPI.h>

#include <WiFly.h>


#include "Credentials.h"



byte server[] = { 66, 249, 89, 104 }; // Google


WiFlyClient client("google.com", 80);


void setup() {

  

  Serial.begin(9600);


  WiFly.begin();

  

  if (!WiFly.join(ssid, passphrase)) {

    Serial.println("Association failed.");

    while (1) {

      // Hang on failure.

    }

  }  


  Serial.println("connecting...");


  if (client.connect()) {

    Serial.println("connected");

    client.println("GET /search?q=arduino HTTP/1.0");

    client.println();

  } else {

    Serial.println("connection failed");

  }

  

}


void loop() {

  if (client.available()) {

    char c = client.read();

    Serial.print(c);

  }

  

  if (!client.connected()) {

    Serial.println();

    Serial.println("disconnecting.");

    client.stop();

    for(;;)

      ;

  }

}


 




우선 'WiFly' 모듈의 라이브러리를 사용하기 위해 'WiFly.h" 파일을 추가한다. 접속할 AP의 SSID와 패스워드가 저장된 'Credentials.h' 파일도 추가해준다. 



 #include <WiFly.h>

 #include "Credentials.h"

 


참고로, "#include" 구문 뒤에 ""(쌍따옴표)가 오는 경우와 <>(부등호)가 오는 경우의 차이점은 헤더 파일이 저장된 위치이다. 컴파일러가 기본으로 참조하고 있는 경로에 헤더 파일이 존재할 경우 <>를 사용하며, 현재 소스 파일이 존재하고 있는 위치 또는 그 하위 경로에 헤더 파일이 존재할 경우 ""를 사용한다. 그냥 여담.



그리고 'WiFlyClient' 객체를 선언한다. 



 WiFlyClient client("google.com", 80);



WiFlyClient 클래스의 생성자는 두 가지 타입으로, 각 매개 변수는 다음과 같다. 




WiFlyClient(byte *ip, int port) - 생성자

WiFlyClient(char *domain, int port) - 생성자



 

 매개 변수


 ip : 접속할 서버의 IP 주소 값이 저장된 byte형 배열

 domain : 접속할 서버의 도메인 주소 값이 저장된 char형 배열

 port : 서버와 연결할 포트 번호


 



위 예제에서는 도메인 주소인 "google.com"과 포트 번호 80을 매개 변수로 사용하여 WiFlyClient 객체를 생성한다. "google.com" 대신 그 윗 줄에 정의된 byte형 배열 'server'를 매개 변수로 사용해도 좋다. 'server'에 저장된 값은 구글의 서버 IP 주소이다. 



WiFlyClient 객체는 서버에 접속을 요청하고, 데이터를 요청하기 위해 사용된다. 위에서 설명한 Server/Client 방식의 접속 단계에서 클라이언트가 행하는 동작들이다. loop() 함수에서 자세히 살펴보고, 우선 setpu() 함수. 



 WiFly.begin():


 if(!WiFly.join(ssid, passphrase)) {

   Serial.println("Association failed.");

   while(1) {

   }

 }

 



위 부분은 WiFly 모듈을 초기화하고, 지정된 AP로 접속을 시도하는 구문이다. 




WiFly.begin()


WiFly 모듈을 초기화한다. SPI 통신에 대한 초기화와 하드웨어 적인 초기화가 진행되므로, WiFly 모듈의 사용을 위해 반드시 맨 처음에 실행되어야 한다. 




boolean WiFly.join(char *ssid)

boolean WiFly.join(char *ssid, char *password)


매개 변수로 전달된 SSID 값으로 AP를 검색하여 접속한다. 접속이 완료되면 WiFly 모듈에 IP가 할당되며 TRUE가 반환된다. 만일 AP를 찾지 못하거나 패스워드 오류 등으로 접속에 실패하면 FALSE 값이 반환된다. 



 

 매개 변수


 ssid : 접속할 AP의 SSID 값이 저장된 문자형 배열

 password : 접속할 AP의 패스워드 값이 저장된 문자형 배열


 반환 값


 boolean : 접속 성공 여부. 성공일 경우 TRUE, 실패일 경우 FALSE가 반환된다. 






만일 WiFly.join() 함수 실행 시 FALSE 값이 반환될 경우 "Association failed."라는 문구를 시리얼로 출력한 후 동작을 멈춘다. (while() 함수에 종료 조건이 존재하지 않으므로 무한 루프에 빠지게 됨, 이 경우 loop() 함수도 동작하지 않는다.)



접속이 정상적으로 이뤄지고 IP 할당이 끝나면 WiFlyCient 객체를 이용하여 저장된 서버에 접속한다. 



 if(client.connect()) {

   Serial.println("connected");

   client.println("GE /search?q=arduino HTTP/1.0");

   client.println();

 } else {

   Serial.println("connection failed");

 }

 




boolean WiFlyClient.connect()



저장된 IP 주소 또는 도메인 주소로 접속을 요청한다. 해당 서버에서 접속을 승인하였을 경우 TRUE가 반환되며, 접속에 실패했을 경우 FALSE가 반환된다. 



 

 매개 변수


 없음


 반환 값


 boolean : 접속 승인 결과 값. 성공 시 TRUE, 실패 시 FALSE가 반환.

 

 



접속 요청 결과 TRUE가 반환되면 WiFlyClient 객체는 WiFlyClient.print() 또는 WiFlyClient.println() 함수를 이용하여 서버로 데이터를 전송한다. 




WiFly.print(value)

WiFly.println(value)



접속된 서버로 데이터를 전송한다. 문법은 Serial.print() 또는 Serial.println() 함수와 동일하다. 



 

 매개 변수


 value : 전송할 데이터. 문자열, 문자, 정수, 실수, Boolean 형의 변수 값이 사용될 수 있다. 


 




위 예제에서는 "GET /search?q=arduino HTTP/1.0"이라는 문자열을 전송한다. 이 구문은 HTML 구문으로, 서버에 정보를 요청하기 위한 명령이다. HTML에 관한 내용은 강좌의 주제와 관련이 없으므로 직접 언급하지는 않는다. (사실 잘 몰라..) 그냥 첫 페이지에 대한 정보를 요청하는 명령어라고 알아두고 넘어가자. 



여기까지가 setup() 함수. 



잉? 요청하고 끝??brown_and_cony-17




다음은 loop() 함수에서 처리한다. 



 if(client.available()) {

   char c = client.read();

   Serial.print(c);

 }

 



엇? 많이 보던 구문이다!



위의 WiFlyClient.println() 함수도 그렇고, 많이 보던 함수들이 나오는 건 같은 기능을 수행하는 함수들이기 때문. 객체지향 언어의 장점이지. 끄덕끄덕.


아무튼, 기능은 이미 알고 있는 함수들이다. 




int WiFlyClient.available()


서버로부터 수신된 데이터의 길이를 반환한다. 수신된 데이터가 없을 경우 0을 반환한다. 



int WiFlyClient.read()


서버로부터 수신된 데이터를 한 바이트씩 읽어온다. 




읽어 온 데이터는 시리얼을 통해 출력한다. 




 if(!client.connected()) {

   Serial.println();

   Serial.println("disconnecting");

   client.stop();

   for( ; ; )

     ;

 }

 



WiFlyClient.connected() 함수는 서버와의 접속 상태를 반환하는 함수이다. WiFlyClient.connect() 함수와 혼동하지 않도록 하자. 


만일 접속 상태가 아닐 경우 연결을 종료한 후 "while(1)" 구문과 마찬가지로 종료 조건이 없는 "for( ; ; )" 구문을 사용해 동작을 멈춘다. (for 함수를 무한히 반복하게 되어 더 이상 loop() 함수가 반복되지 않는다.)




boolean WiFlyClient.connected()


서버와의 접속 상태를 반환한다. 접속 중일 경우 TRUE, 접속 상태가 아닐 경우 FALSE를 반환한다. 



WiFlyClient.stop()


서버와의 연결을 종료한다. 매개 변수와 반환 값은 없다. 




자, 그럼 업로드한 후 시리얼 모니터 창을 열어보자. WiFly 모듈이 AP에 접속하기 위해서는 5~10초 정도의 시간이 소요되므로 잠시 기다리세효. 


아래와 같은 화면이 나타나는가?


57261d512bf9cf3cf7e0b3eb49d2ea64.png


맨 마지막 줄의 "disconnecting." 문장 이전까지의 내용이 바로 구글 서버에서 아두이노로 전송한 데이터이다. 정확히 말하자면 클라이언트인 아두이노가 서버인 구글에게 "GET ~" 구문으로 요청한 것에 대한 응답이라고 볼 수 있다. 



요청에 대한 응답이 완료되면 연결 종료.



짝짝짝!

brown_and_cony-35 



만일 위 화면과 같은 데이터가 출력되지 않고 "Association failed."라는 문구가 출력된다면 AP 접속에 실패한 것이므로 SSID와 패스워드, 또는 AP의 상태를 확인해야 한다. 


또는 AP에는 접속되었지만 "connection failed"라는 구문이 출력된다면 서버의 IP 주소 또는 도메인 주소가 올바른지 확인해야 한다. 접속한 AP가 인터넷에 연결되어 있지 않을 경우에도 발생할 수 있다. 


또는 한참이 지나도 아무 문구도 출력되지 않거나 알 수 없는 에러 메시지가 출력된다면 모듈 자체의 오류일 수 있으므로 핀 연결 상태나 모듈의 불량 여부를 확인해야 한다. (보통 SPI 통신에 오류가 있을 경우 주로 발생)



이상, WebClient 예제에 대한 강좌를 마친다. 다음 강좌에서는 WebServer 예제를 실습해보도록 하자. 그럼 이만, 안녕!

0
0
이 글을 페이스북으로 퍼가기 이 글을 트위터로 퍼가기 이 글을 카카오스토리로 퍼가기 이 글을 밴드로 퍼가기

임베디드 보드

번호 제목 글쓴이 날짜 조회수
118 아두이노 ESP32 Analog Inputs (ADC) +4 icon 양재동메이커 02-12 16,137
117 아두이노 TIP : Serial의 Port가 Open 시점 확인 icon 양재동메이커 01-21 12,990
116 아두이노 ESP32 Boot Mode icon 양재동메이커 12-28 12,835
115 아두이노 아두이노 에러 리스트(Arduino Error list) icon 양재동메이커 11-24 17,817
114 아두이노 ESP32 main.cpp +1 icon 양재동메이커 11-19 13,181
113 아두이노 ESP32 EEPROM 와 IR Remote icon 양재동메이커 08-06 13,073
112 아두이노 Learn ESP32 icon 양재동메이커 06-25 12,655
111 라즈베리 파이 라즈베리 파이 (Raspberry Pi) 기초 icon 양재동메이커 06-19 14,149
110 라즈베리 파이 (동영상 강의) 라즈베리 파이 강좌 Link icon 양재동메이커 06-17 13,247
109 STM32 / MBED [MED] Switch debouncing icon HellMaker 12-30 15,226
108 기타 [타이젠] 아두이노의 16x2 LCD Display라이브러리 LiquidCrystal_I2C의 타이젠 포팅 icon 양재동메이커 09-15 14,802
107 기타 [타이젠] GPIO의 디지탈 출력과 입력 인터럽트의 C++ Class 제작 icon 양재동메이커 09-12 14,280
106 마이크로비트 서보 모터 icon HellMaker 09-03 14,097
105 마이크로비트 아날로그 온도센서 (마이크로 비트 센서 활용) icon HellMaker 09-01 14,605
104 마이크로비트 터치센서 (마이크로 비트 센서 활용) icon HellMaker 09-01 13,718
103 마이크로비트 디지털 홀 센서 (마이크로 비트 센서 활용) icon HellMaker 08-29 12,900
102 마이크로비트 리니어 홀 센서 (마이크로 비트 센서 활용) icon HellMaker 08-29 12,454
101 마이크로비트 불꽃 감지 센서 (마이크로 비트 센서 활용) icon HellMaker 08-26 12,793
100 마이크로비트 로터리 엔코더 (마이크로 비트 센서 활용) icon HellMaker 08-25 12,899
99 마이크로비트 2컬러 LED(3mm) (센서 활용) icon HellMaker 08-22 12,899