블로그 이미지
문슐랭 upip57@naver.com
진짜귀찮음

Notice

Recent Post

Recent Comment

Recent Trackback

Archive

calendar

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
  • total
  • today
  • yesterday
2017. 1. 10. 14:03 프로그래밍/C 언어

 C언어 소켓프로그래밍 - Http request -  response


참조 사이트 모음


 http://mintnlatte.tistory.com/

☞ http://forum.falinux.com/zbxe/?mid=network_programming

http://m.blog.naver.com/sarah7_2000/80203615486

☞ http://kyh1026.tistory.com/76



오랫만에 포스팅을 하네요 ㄷㄷ.... 허허..... 소스설명은 아래쪽에 배치해 두겠습니다.


아마 양에 따라 1~2 편으로 나뉠지도 모르겠네요. 

길면 지루해 지거든요. 보기도 힘들고....

 


 Http request -  response (C-소스코드)



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
#include <stdio.h>
#include <WinSock2.h>
#include <Windows.h>
#pragma comment(lib,"ws2_32.lib")
 
#define BUFF_SIZE 1024
 
int main()
{
    WSADATA wsa;
    struct hostent *host;
    char msg[BUFF_SIZE]; //나중에 결과값을 저장하기 위한 선언
 
    if (WSAStartup(MAKEWORD(22), &wsa) != 0)
    {
        perror("WSAStart Error ");
        system("pause");
        return -1;
    }
 
    SOCKET sock = socket(PF_INET, SOCK_STREAM, 0);
    SOCKADDR_IN addr;
 
    if (sock == INVALID_SOCKET)
    {
        perror("Sock Error ");
        system("pause");
        return -1;
    }
    host = gethostbyname("www.google.co.kr");
 
    addr.sin_family = AF_INET;
    addr.sin_port = htons(80);
    addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr*)*host->h_addr_list));
 
    if(connect(sock,(SOCKADDR*)&addr,sizeof(addr)) == SOCKET_ERROR) 
    {
        printf("Not Connect \n");
        system("pause");
        return 1;
    }
    send(sock, "GET / HTTP/1.1\r\nHost: www.google.co.kr\r\n\r\n", strlen("GET / HTTP/1.1\r\nHost: www.google.co.kr\r\n\r\n"), 0);
    recv(sock,msg,BUFF_SIZE,0);
 
    printf("%s \n",msg);

    closesocket(sock);
    WSACleanup();
    system("pause");
    
    return 0;
}
cs



 Http request -  response 실행화면





 Http request -  response 소스설명



#include <WinSock2.h>



일단 소켓프로그래밍을 하기 위해 아래와 같이 WinSock2.h 가 필요합니다.


그리고 아래와 같이 전처리기를 하나 선언 해 줍니다.


#pragma comment(lib,"ws2_32.lib")



pragma comment 전처리기는

#pragma comment(comment -type,["comment string"]) 의 형식을 이용해서 사용돼 집니다.


(이 방법이 아니면 프로젝트 속성에서 링커 설정해 주는 방법도 있습니다. 위가 편하더라구요.)


제가 선언한 것 처럼 라이브러리를 선언해주는 게 가장 일반 적인 방법이라고 하더군요.


자세한 내용은 아래 블로그 링크를 참조해 주시면 될 듯 합니다. 정리를 잘 해두었더군요.


http://kyh1026.tistory.com/76



이제 소켓을 본격적으로 만들어 볼 거에요 ㅎ

WinSock2.h 안에 있는 WSADATA 구조체를 불러와 초기화를 해줍니다. 무조건 해주어야하는 작업이에요. 소켓을 위해 ㅠ



WSADATA wsa;



WSAData 구조체에 들어가 있는 내용들이에요 MS 홈페이지에서 가져 온 내용이에요.

한번 레퍼런스에 대해 읽어보시는 것도 괜찮다고 생각되서 가져 왔습니다.

링크 걸어 드릴게요 ㅎ



☞  https://msdn.microsoft.com/ko-kr/library/37k8e5x7(v=vs.110).aspx



struct WSAData {
   WORD wVersion;
   WORD wHighVersion;
   char szDescription[WSADESCRIPTION_LEN+1];
   char szSystemStatus[WSASYSSTATUS_LEN+1];
   unsigned short iMaxSockets;
   unsigned short iMaxUdpDg;
   char FAR * lpVendorInfo;
};



이제 윈속을 초기화가 되었으니 열어준다? 시작해준다? 어떤 표현이 더 적절한지 음......

아무튼 전 연다는 표현으로 진행하도록 하겠습니다.

(정확한 표현은 댓글로 부탁드리겠습니다...ㅠ 허허.... 굽신굽신...)


아래 코드는 소켓을 열어준 후 소켓 버젼을 비교해주는 코드 입니다.


이게 버젼이 맞으면 0 을 반환 하게 됩니다. 그렇기 때문에 0 이 아니면 오류가 발생 했다!!

라고 볼 수 있는 것이죠.

(지금은 간단한 소켓이지만 복잡해 지면 오류 내용이 매우 중요하다고 합니다.)



    if (WSAStartup(MAKEWORD(22), &wsa) != 0)
    {
        perror("WSAStart Error ");
        system("pause");
        return -1;
    }



일단 WSAStartup 의 구조체는 이런 모양으로 생겼군요.


https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms742213(v=vs.85).aspx



int WSAStartup(
  _In_  WORD      wVersionRequested,
  _Out_ LPWSADATA lpWSAData
);



이제  MAKEWORD(22) 에 대해 알아보도록 하죠.
WinSock2.h 파일 안의 매크로 중 하나 입니다. (주버젼, 보조버젼) 의 형식으로 사용 됩니다.
헤더파일 내부의 메크로 소스를 가져 와 보았습니다.


#define MAKEWORD(low,high) \

        ((WORD)(((BYTE)(low)) | ((WORD)((BYTE)(high))) << 8))



이때 왜 하필 버젼이 2 냐? 라는 의문점을 가질 수 가 있겠죠? 제가 그랬거든요... 허허...
버젼 막 9 도 너어보고 막 넣어 보았는데 오류는 나오지 않더라구요.... 이상하게시리........
근데 2.2 이것을 사용하는 것이 가장 좋을 듯 보이네요.

궁금해서 해더 파일에서 찾아보았는데 83-85 라인에서 이것을 발견 했습니다.


#ifndef WINSOCK_VERSION
#define WINSOCK_VERSION MAKEWORD(2,2)
#endif


이래서 다들 2.2 로 입력해서 사용하시는 것 같아요.



이제는 아래 코드에대해 알아 보도록 하죠.

- 이 코드를 끝으로 1편을 끝낼 생각입니다.


    SOCKET sock = socket(PF_INET, SOCK_STREAM, 0);
    SOCKADDR_IN addr;



SOCKET 변수 로 소켓을 생성해볼까요?


레퍼런스: int socket(int domain, int type, int protocol); 으로 사용됩니다.


PF_INET 는 IPv4 프로토콜을 뜻함.

SOCK_STREAM 은 연결지향을 뜻함. (SOCK_DGRAM 은 비연결성을 뜻함)

● 0 은 특정 프로토콜을 사용하는 부분인데 보통 0을 쓴다고 합니다.


socket() 에 관련해 제가 참조한 사이트를 링크 걸겠습니다. 

정말 자세하게 나와있으므로 세부적인 부분은 여기서 공부하시면 될 듯 합니다.



http://forum.falinux.com/zbxe/index.php?document_srl=429387&mid=C_LIB



이제 SOCKADDR_IN 구조체는 구조체 내용만 보고 다음 2편에서 계속 다루도록 하겠습니다.

(생각보다 더 길어졌네요.....)



struct sockaddr_in{
   short sin_family;
   unsigned short sin_port;
   struct in_addr sin_addr;
   char sin_zero[8]; 

};



레퍼런스 MS 링크


https://msdn.microsoft.com/ko-kr/library/zx63b042(v=vs.110).aspx



2편에서 계속!!


posted by 진짜귀찮음