logo

English

이곳의 프로그래밍관련 정보와 소스는 마음대로 활용하셔도 좋습니다. 다만 쓰시기 전에 통보 정도는 해주시는 것이 예의 일것 같습니다. 질문이나 오류 수정은 siseong@gmail.com 으로 주세요. 감사합니다.

iOS,OSX - CFSocket 사용법

by digipine posted Nov 01, 2017
?

Shortcut

PrevPrev Article

NextNext Article

Larger Font Smaller Font Up Down Go comment Print
?

Shortcut

PrevPrev Article

NextNext Article

Larger Font Smaller Font Up Down Go comment Print
CFSocket 은 BSD Socket 과 유사합니다. BSD Socket 에서 사용하는 sockaddr_in 을 사용하는 점도 동일합니다. BSD Socket 보다 편리한 점은 Socket 으로 데이터가 들어올 경우를 별도로 프로그래밍해주지 않아도 이것을 Callback 으로 처리해 줄 수 있도록 설계되어 있다는 점입니다.
 
먼저 아래 4개의 헤더를 포함시킵니다.
#import <sys/types.h>
#import <sys/socket.h>
#import <netinet/in.h>
#import <netdb.h>
 
Socket 의 생성은 다음과 같습니다.
// Network connection
ref = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, 0, 
                     kCFSocketReadCallBack|kCFSocketDataCallBack|kCFSocketConnectCallBack|kCFSocketWriteCallBack,
                     CFSockCallBack, NULL);
 
첫번째 파라미터는 오브젝트 생성을 위해 메모리할당을 해줄 할당자를 지정하는 곳입니다. kCFAllocatorDefault 혹은 0 을 설정하면 디폴트 할당자가 그 일을 맡습니다. PF_INET 은 인터넷 프로토콜, SOCK_STREAM 은 스트리밍 소켓타입을 의미합니다. 4 번째 항목은 프로토콜인데 0 을 설정할 경우 3번째 항목이 SOCK_STREAM 이라면 IPROTO_TCP, SOCK_DGRAM 이라면 IPROTO_UDP 로 자동설정이 됩니다. 물론 IPROTO_TCP 라고 명시적으로 써주셔도 됩니다. 5번째 항목이 Callback 조건을 지정해주는 것인데 콜백 타입은 아래와 같이 정의되어 있습니다.
 
enum CFSocketCallBackType {
   kCFSocketNoCallBack = 0,
   kCFSocketReadCallBack = 1,
   kCFSocketAcceptCallBack = 2,
   kCFSocketDataCallBack = 3,
   kCFSocketConnectCallBack = 4,
   kCFSocketWriteCallBack = 8
};
 
클라이언트 소켓의 경우는 Read, Data, Connect, Write 정도의 콜백을 설정해주면 되겠습니다. Accept 는 서버소켓인 경우 설정합니다.
6번째 항목은 Callback 함수를 지정해주는 곳입니다. CFSockCallBack 이라고 이름지어봤습니다. 마지막 항목은 Socket 컨텍스트 정보를 받기 위한 곳입니다. 안 받으려면 NULL 로 지정합니다.
 
더 공부하실 분들을 위해, 소켓생성 함수의 원형은 아래와 같습니다.
 
CFSocketRef CFSocketCreate (
   CFAllocatorRef allocator,
   SInt32 protocolFamily,
   SInt32 socketType,
   SInt32 protocol,
   CFOptionFlags callBackTypes,
   CFSocketCallBack callout,
   const CFSocketContext *context
);
 
 
소켓이 생성된 후에는 BSD Socket 과 동일하게 remote address 를 정해주고 연결해야 합니다.
 
struct sockaddr_in theName;
struct hostent *hp;
    
theName.sin_port = htons(80);
theName.sin_family = AF_INET;
    
hp = gethostbyname("naver.com");
if( hp == NULL ) {
    return;
}
memcpy( &theName.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length );
 
이렇게 만들어진 sockaddr_in 구조체를 이용해서 접속에 사용될 CFData 레퍼런스를 만듭니다.
 
CFDataRef addressData = CFDataCreate( NULL, &theName, sizeof( struct sockaddr_in ) );
 
소켓과 어드레스데이터가 만들어졌으므로 이제 connect 하면 되겠죠?
 
CFSocketConnectToAddress(ref, addressData, 30);
 
30은 timeout 이며 초단위지정입니다. 만약 음수값이 주어지면 CFSocketConnectToAddress 는 즉각 반환되며, 백그라운드에서 접속을 시도합니다. 접속이 이루어지면 Socket 생성때 사용했던 CallBack 함수가 호출됩니다.
 
 
CFRunLoopSourceRef FrameRunLoopSource = CFSocketCreateRunLoopSource(NULL, ref , 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), FrameRunLoopSource, kCFRunLoopCommonModes); 
 
이 두줄은 소켓에 대한 LoopSource 를 만들고 이 LoopSource 를 실행하는 명령입니다. 이 두줄이 아주 편리한 부분인데, 이로서 특별히 Callback 에 대한 프로그래밍(Thread 나 기타 프로세스 제어)이 없이도 Callback 을 사용할 수 있도록 해줍니다.
 
 
이제 Callback 부분을 보겠습니다.
 
void CFSockCallBack (
                     CFSocketRef s,
                     CFSocketCallBackType callbackType,
                     CFDataRef address,
                     const void *data,
                     void *info
) {
 
    NSLog(@"callback!");
    if(callbackType == kCFSocketDataCallBack) {
        NSLog(@"has data");
        // 데이터 수신시 여기에 프로그래밍하세요
        UInt8 * d = CFDataGetBytePtr((CFDataRef)data);
        int len = CFDataGetLength((CFDataRef)data);
        for(int i=0; i < len; i++) {
            NSLog(@"%c",*(d+i));
        }
    }
    if(callbackType == kCFSocketReadCallBack) {
        NSLog(@"to read");
        // 소켓에서 읽을 수 있습니다.
        char buf[100] = {0};
        int sock = CFSocketGetNative(s);
        NSLog(@"to read");
        NSLog(@"read:%d",recv(sock, &buf, 100, 0));
        NSLog(@"%s",buf);
    }
    if(callbackType == kCFSocketWriteCallBack) {
        NSLog(@"to write");
        // 데이터 송신이 가능해졌습니다.
        char sendbuf[100]={0};
        strcpy(sendbuf,"GET / HTTP/1.0\r\n\r\n");
        CFDataRef dt = CFDataCreate(NULL, sendbuf, 100);
        CFSocketSendData(s, NULL, dt, strlen(sendbuf));
    }
    if(callbackType == kCFSocketConnectCallBack) {
        NSLog(@"connected");
        // 연결이 이루어졌습니다.
    }
}
 
대략 이런 형태를 가집니다. 물론 각각의 callbackType 에 대해 프로그래밍을 해주어야겠죠.
주의 사항은, CallbackType 에 kCFSocketDataCallBack 을 포함시켰을 경우 kCFSocketReadCallBack 은 호출되지 않습니다. kCFSocketDataCallBack 을 설정하면 Socket 으로 들어오는 데이터는 자동으로 읽혀지며 읽혀진 데이터는 CFData 형식으로 data 포인터로 전달되어집니다. kCFSocketDataCallBack 이 Callback type 에 지정되지 않았을 경우는 kCFSocketReadCallBack 이 수행되어야 하며 이때는 소켓으로부터 직접 데이터를 읽어주어야 합니다. 읽을 데이터가 남아있을 때까지 콜백은 계속 호출됩니다.
위의 경우는 Socket Creation 시 kCFSocketDataCallBack 을 지정해주었기 때문에 데이터가 자동으로 읽혀졌습니다. 만약 소켓생성시에 kCFSocketDataCallBack 을 콜백타입으로 지정해주지 않았다면 kCFSocketReadCallBack 을 처리해주어야 하며 예제에서처럼 recv 함수들을 통해 직접 데이터를 읽어야 합니다.

List of Articles
No. Subject Author Date Views
36 iOS - Socket Nagle 알고리듬 OFF digipine 2017.11.01 208
35 iOS - Thread Loop 내에서 UI 업데이트 방법 digipine 2017.11.01 211
34 iOS - UILabel 에서 AttributeString 사용하기 digipine 2017.11.02 640
33 iOS - UITextField의 Placeholder Color 색 변경하기 file digipine 2017.11.02 1152
32 iOS - View 이동 전환 하기 총정리 digipine 2017.11.01 537
31 iOS - 코드 수행시간 측정하기 - getTickCount digipine 2017.11.01 848
» iOS,OSX - CFSocket 사용법 digipine 2017.11.01 444
29 macOS ARP Spoofing Attack file digipine 2020.09.17 694
28 macOS Daemon 관련 시스템 폴더 목록 lizard2019 2024.03.08 29
27 MacOS mysql 비밀번호 분실 시 재설정하기 digipine 2017.11.14 1029
26 OpenAL PDF, Sample Source file digipine 2017.11.02 796
25 OSX - Screen Serial Terminal - OSX에서 시리얼 터미널 사용하기 digipine 2017.11.03 6871
24 OSX 사파리 최신 버전 폰트 변경하기 file digipine 2017.11.03 1224
23 The distance estimate iBeacon signal strength lizard2019 2019.10.25 695
22 WatermelonDB 'jsi/jsi.h' file not found 문제 해결 file digipine 2021.04.06 733
21 XCode 8 업데이트 후 Code Sign Error 발생 시 해결법 1 digipine 2017.11.02 711
20 [iOS, MacOS] ATS 보안 정책 가이드 digipine 2017.11.02 570
19 [iOS, MacOS] NSArray 정렬 Sorting에 대해서 digipine 2017.11.02 667
18 [iOS, MacOS] NSNotification, NSNotificationCenter 사용법 digipine 2017.11.02 1026
17 [iOS, MacOS] Singleton 싱글톤 패턴 사용하기 2 digipine 2017.11.02 1080
Board Pagination Prev 1 2 3 Next
/ 3