動機
65507バイトのデータをまるっと別なところに送りたい。だけどせっかくなので、
ちょっと低レベルAPIで遊んで見たくなりました。
なのでちょっと不慣れですがudpソケット通信を試して見ようと思います。
環境
ios9.2.1, osx 10.11.1, xcode 7.2.1になります。
実装(ios: 送信側)
#import "ViewController.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
@implementation ViewController {
NSTimer *_timer;
int _index;
}
- (void)viewDidLoad {
[super viewDidLoad];
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 60.0 target:self selector:@selector(tick:) userInfo:nil repeats:YES];
}
- (void)tick:(id)sender {
const int kSendSize = 65507;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(3000);
addr.sin_addr.s_addr = inet_addr("192.168.10.3");
int maxsize = kSendSize;
int r = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &maxsize, sizeof(int));
assert(r == 0);
char bytes[kSendSize] = "";
sprintf(bytes, "index = %d", _index);
ssize_t s = sendto(sock, bytes, sizeof(bytes), 0, (struct sockaddr *)&addr, sizeof(addr));
if(s != kSendSize) {
printf("failed to sendto: errno = %d, %s\n", errno, strerror(errno));
}
close(sock);
_index++;
}
@end
実装(osx: 受信側)
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, const char * argv[]) {
const int kSendSize = 65507;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(3000);
addr.sin_addr.s_addr = INADDR_ANY;
bind(sock, (struct sockaddr *)&addr, sizeof(addr));
for(int i = 0 ; i < 10000 ; ++i) {
char buf[kSendSize] = {0};
ssize_t r = recv(sock, buf, sizeof(buf), 0);
if(r == kSendSize) {
printf("%s\n", buf);
}
}
close(sock);
return 0;
}
Note
どうやらsetsockoptで、SO_SNDBUFを広げてあげないとうまく送れないようでした。
また、通信頻度を、1.0 / 60.0から1.0 / 120など上げてみると、
頻繁に、failed to sendto: errno = 55, No buffer space available
とエラーが吐かれて通信が不安定になるようでした。
帯域がいっぱいになった、ということのようです。
windows (vvvv)
今日から始めたvvvvなら、
iosからのudp送信、そのまま受信することができます。
素晴らしく簡単です
まとめ
低レベルAPIは得てして面倒だったり複雑になりがちです。
しかしながら、UDPの持つ、投げっぱなしでパケットロスを気にしない、という性質もあって、案外シンプルな実装で通信をすることができて少し驚いています。今までちょっと毛嫌いしていましたが、下手に高レベルなライブラリを使うよりも、実はこちらのほうがメリットが大きい場面もあるかもしれません。
参考
以下ページ等を参考にさせていただきました。
ソケット入門
http://software.aufheben.info/kouza/senior/kouza_socket.html
UDPを使う
http://www.geekpage.jp/programming/linux-network/udp.php