読者です 読者をやめる 読者になる 読者になる

なかじまの開発ブログ

アプリ開発における備忘録などなど。

MENU

UDP通信で送信、受信、タイムアウト処理【Objective-C】

Objective-C
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#import <sys/types.h>

bool readflag; // 受信したかどうか 初期値はfalseを代入しておく

送信

// 送信
- (void)dataSend:(NSString *)text {
  char *cstr = (char *)[text UTF8String]; // 送信したいテキストをchar型に変換

  // ソケットの作成
  CFSocketRef socket = CFSocketCreate(NULL, PF_INET, SOCK_DGRAM, IPPROTO_UDP, kCFSocketNoCallBack, NULL, NULL);

  struct sockaddr_in addr;
  addr.sin_len = sizeof(struct sockaddr_in);
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = addr.sin_addr.s_addr = inet_addr((char *)[@"送り先のIPアドレス" UTF8String]);
  addr.sin_port = htons(ポート番号);
  CFDataRef address = CFDataCreate(NULL, (UInt8*)&addr, sizeof(struct sockaddr_in));
  
  CFDataRef senddata = CFDataCreate(NULL, (UInt8*)cstr, strlen(cstr));

  // 送信
  CFSocketSendData(socket, address, senddata, 3);

  // 解放
  CFRelease(socket);
  CFRelease(address);
  CFRelease(senddata);
}

受信

// 受信
- (void)dataRead {
  dispatch_group_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), dispatch_group_create(), ^{
    char buf[2048];

    memset(buf, 0, sizeof(buf)); // 初期化

    // ソケットの作成
    int socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    // 受信アドレス
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(ポート番号)
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_len = sizeof(addr);

    // バインド
     bind(sock, (struct sockaddr*)&addr, addr.sin_len);

    // 受信
    int size = (int)recvfrom(sock, buf, sizeof(buf), 0, NULL, NULL);
    if (size > 0) {
      NSString *getdataText = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding];
      
      if((getdataText isEqualToString:@"End"]) {
        // 受信したデータが、タイムアウトで送信した文字列だった場合
        readflag = false; // 受信失敗(タイムアウト)
      } else {
        readflag = true;  // 受信成功
      }
    } else {
      NSLog(@"データなし");
    }
    close(sock);
  });
}

タイムアウト

自分で自分に何かしらを送ってやる

// タイムアウト
- (void)timeoutSend {
  NSString *text = @"End";

  char *cstr = (char *)[text UTF8String]; // 送信したいテキストをchar型に変換

  // ソケットの作成
  CFSocketRef socket = CFSocketCreate(NULL, PF_INET, SOCK_DGRAM, IPPROTO_UDP, kCFSocketNoCallBack, NULL, NULL);

  struct sockaddr_in addr;
  addr.sin_len = sizeof(struct sockaddr_in);
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = addr.sin_addr.s_addr = inet_addr((char *)[@"自分のIPアドレス" UTF8String]);
  addr.sin_port = htons(ポート番号);
  CFDataRef address = CFDataCreate(NULL, (UInt8*)&addr, sizeof(struct sockaddr_in));
  
  CFDataRef senddata = CFDataCreate(NULL, (UInt8*)cstr, strlen(cstr));

  // 送信
  CFSocketSendData(socket, address, senddata, 3);

  // 解放
  CFRelease(socket);
  CFRelease(address);
  CFRelease(senddata);
}

使い方

送信処理をしたいメソッド内で(ボタン押下メソッドとか)

// 送信
[self dataSend:@"送信したいテキスト"];

// 受信
[self dataRead];

NSDate *start = [NSDate date];

while(1) {
  if (readflag == true) break; // 受信成功したならループを抜ける
  else {
    // 経過時間を取得して、指定した時間がたったらループを抜ける(この場合は5秒)
    if (-[start timeIntervalSinceNow] == 5) break;
  }
}

if (readflag == true) {
  readflag = false;

  // 受信後の処理
} else {
  // タイムアウト
  [self timeoutSend];
}