So it seems to me that I cannot use the same socket to send and receive UDP data?
It’s not that simple. Below you’ll find pasted in some simple UDP test code which will happily send and receive from the same socket. In this example:
The view controller manages a table view with two items, one to send and another to receive.
I ran it on my iPhone, running 10.2, which was on my office Wi-Fi.
192.168.1.189 is the IP address of my Mac on the same Wi-Fi.
192.168.1.184 is the IP address of my iPhone.
I tested the send and receive by running
nc
on my Mac, as shown below.
$ nc -u -l 12345
Hello Cruel World! 2016-12-21 10:09:34 +0000
Hello Cruel World! 2016-12-21 10:10:45 +0000
…
$ nc -u 192.168.1.184 12345
Hello iPhone 1!
Hello again iPhone!
…
I recommend that you repeat my test and see if you get the same results. If you do, you can then try to modify the test to reproduce the problem you’re seeing.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"
#import "MainViewController.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
@interface MainViewController ()
@property (nonatomic, assign, readwrite) int sock;
@end
@implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.sock = -1;
}
- (void)sendTest {
struct sockaddr_in addr = {
.sin_len = sizeof(struct sockaddr),
.sin_family = AF_INET,
.sin_port = htons(12345),
.sin_addr.s_addr = inet_addr("192.168.1.189")
};
NSString * message = [NSString stringWithFormat:@"Hello Cruel World! %@\r\n", [NSDate date]];
NSData * messageData = [message dataUsingEncoding:NSUTF8StringEncoding];
ssize_t bytesSent = sendto(
self.sock,
messageData.bytes,
messageData.length,
0,
(const struct sockaddr *) &addr,
sizeof(addr)
);
if (bytesSent < 0) {
NSLog(@"send failed: %d", errno);
} else {
NSLog(@"sent %zd bytes", bytesSent);
}
}
- (void)receiveTest {
struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
NSMutableData * bufferData = [[NSMutableData alloc] initWithLength:2048];
ssize_t bytesReceived = recvfrom(
self.sock,
bufferData.mutableBytes,
bufferData.length, 0,
(struct sockaddr *)
&addr,
&addrLen
);
if (bytesReceived < 0) {
if (errno == EAGAIN) {
NSLog(@"nothing to receive");
} else {
NSLog(@"received failed: %d", errno);
}
} else {
char host[NI_MAXHOST];
bufferData.length = (NSUInteger) bytesReceived;
BOOL success = getnameinfo(
(const struct sockaddr *) &addr,
addrLen,
host,
sizeof(host),
NULL,
0,
NI_NUMERICHOST | NI_NUMERICSERV
) == 0;
assert(success);
NSLog(@"received %@ from %s", bufferData, host);
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
#pragma unused(tableView)
#pragma unused(indexPath)
if (self.sock == -1) {
self.sock = socket(AF_INET, SOCK_DGRAM, 0);
assert(self.sock >= 0);
BOOL success = fcntl(self.sock, F_SETFL, O_NONBLOCK) == 0;
assert(success);
struct sockaddr_in addr = {
.sin_len = sizeof(struct sockaddr),
.sin_family = AF_INET,
.sin_port = htons(12345)
};
success = bind(self.sock, (const struct sockaddr *) &addr, sizeof(addr)) == 0;
assert(success);
}
switch (indexPath.row) {
case 0: {
[self sendTest];
} break;
case 1: {
[self receiveTest];
} break;
default: {
abort();
} break;
}
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
@end