iPhone과 Mac간에 Bonjour 네트워크를 설정했습니다.bytesWritten,하지만 다른 장치는 NSStreamEventHasBytesAvailable 이벤트를 수신하지 않습니다.
사용자가 Mac에서 제공되는 테이블에서 iPhone의 인터넷 서비스를 선택하면 한 쌍의 스트림이 만들어지고 양쪽에서 열립니다.
iPhone은 코드 (정수)를 Mac으로 전송하여 시작합니다. Mac이 성공적으로 수신합니다.
NSInteger bytesWritten = [self.streamOut write:buffer maxLength:sizeof(uint8_t)];
// bytesWritten is 1.
을하지만 아이폰은 결코 NSStreamEventHasBytesAvailable 이벤트를 얻을 수 없습니다 : 사용자 입력 및 처리를 위해 일시 정지 후
는 맥 아이폰에 코드를 전송하기 시작합니다. 이 시점 직전에 double-check를했고, iPhone의 NSInputStream에있는 streamStatus는 NSStreamStatusOpen 인 2입니다.어떤 아이디어가 잘못되었을 수 있습니까?
업데이트 : Mac을 iPhone으로 정수를 전송 한 최초의 테스트를 실행했습니다. 다시 말하지만, Mac의 출력 스트림에서 1의 bytesWritten을 얻었지만 iPhone에는 NSStreamEventHasBytesAvailable 이벤트가 없었습니다.
그래서 iPhone의 입력 스트림에 문제가있을 것입니다. 하지만 doublechecked :
- 아이폰의 self.streamIn가 제대로
- 아이폰 2 개 NSStreamEventOpenCompleted 이벤트를 수신하는 시간 파일에 NSInputStream로 입력, 나는 스트림 인수의 클래스를 확인한다. 하나는 KindOfClass : [NSOutputStream 클래스], 다른 하나는 그렇지 않습니다.
- iPhone은 NSStreamEventEndEncountered, NSStreamEventErrorOccurred 또는 NSStreamEventNone을 수신하지 않습니다.
- 위에서 언급했듯이 Mac의 출력 스트림에 기록한 다음 iPhone의 입력 스트림 상태는 2입니다. NSStreamStatusOpen입니다.
다음은 iPhone의 입력 스트림을 만드는 데 사용되는 코드입니다. 그것이 C 스타일의 소켓 콜백 함수에서 수행 있기 때문에 그것은 CF 유형을 사용 :
CFReadStreamRef readStream = NULL;
CFStreamCreatePairWithSocket(kCFAllocatorDefault, socketNativeHandle, &readStream, NULL);
if (readStream) {
CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
server.streamIn = (NSInputStream *)readStream;
server.streamIn.delegate = server;
[server.streamIn scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
if ([server.streamIn streamStatus] == NSStreamStatusNotOpen)
[server.streamIn open];
CFRelease(readStream);
}
갱신 2 :
소켓 옵션
유지, 릴리스 : 알라의 코멘트에 대한 정보는 응답 copyDescription 콜백은 NULL로 설정됩니다. optionFlags는 acceptCallback으로 설정됩니다.
소켓 생성 여기
아이폰과 Mac에서 모두 소켓을 설정하는 데 사용되는 방법이다,에서 적응 된 사실이 코드에서 무슨 일이 일어나고 있는지 알아 내 주석 시도 완료 (일) 다양한 튜토리얼과 실험 :
/**
Socket creation, port assignment, socket scheduled in run loop.
The socket represents the port on this app's end of the connection.
*/
- (BOOL) makeSocket {
// Make a socket context, with which to configure the socket.
// It's a struct, but doesn't require "struct" prefix -- because typedef'd?
CFSocketContext socketCtxt = {0, self, NULL, NULL, NULL}; // 2nd arg is pointer for callback function
// Make socket.
// Sock stream goes with TCP protocol, the safe method used for most data transmissions.
// kCFSocketAcceptCallBack accepts connections automatically and presents them to the callback function supplied in this class ("acceptSocketCallback").
// CFSocketCallBack, the callback function itself.
// And note that the socket context is passed in at the end.
self.socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, (CFSocketCallBack)&acceptSocketCallback, &socketCtxt);
// Do socket-creation error checking.
if (self.socket == NULL) {
// alert omitted
return NO;
}
// Prepare an int to pass to setsockopt function, telling it whether to use the option specified in arg 3.
int iSocketOption = 1; // 1 means, yes, use the option
// Set socket options.
// arg 1 is an int. C-style method returns native socket.
// arg 2, int for "level." SOL_SOCKET is standard.
// arg 3, int for "option name," which is "uninterpreted." SO_REUSEADDR enables local address reuse. This allows a new connection even when a port is in wait state.
// arg 4, void (wildcard type) pointer to iSocketOption, which has been set to 1, meaning, yes, use the SO_REUSEADDR option specified in arg 3.
// args 5, the size of iSocketOption, which can now be recycled as a buffer to report "the size of the value returned," whatever that is.
setsockopt(CFSocketGetNative(socket), SOL_SOCKET, SO_REUSEADDR, (void *)&iSocketOption, sizeof(iSocketOption));
// Set up a struct to take the port assignment.
// The identifier "addr4" is an allusion to IP version 4, the older protocol with fewer addresses, which is fine for a LAN.
struct sockaddr_in addr4;
memset(&addr4, 0, sizeof(addr4));
addr4.sin_len = sizeof(addr4);
addr4.sin_family = AF_INET;
addr4.sin_port = 0; // this is where the socket will assign the port number
addr4.sin_addr.s_addr = htonl(INADDR_ANY);
// Convert to NSData so struct can be sent to CFSocketSetAddress.
NSData *address4 = [NSData dataWithBytes:&addr4 length:sizeof(addr4)];
// Set the port number.
// Struct still needs more processing. CFDataRef is a pointer to CFData, which is toll-free-bridged to NSData.
if (CFSocketSetAddress(socket, (CFDataRef)address4) != kCFSocketSuccess) {
// If unsuccessful, advise user of error (omitted)…
// ... and discard the useless socket.
if (self.socket)
CFRelease(socket);
self.socket = NULL;
return NO;
}
// The socket now has the port address. Extract it.
NSData *addr = [(NSData *)CFSocketCopyAddress(socket) autorelease];
// Assign the extracted port address to the original struct.
memcpy(&addr4, [addr bytes], [addr length]);
// Use "network to host short" to convert port number to host computer's endian order, in case network's is reversed.
self.port = ntohs(addr4.sin_port);
printf("\nUpon makeSocket, the port is %d.", self.port);// !!!:testing - always prints a 5-digit number
// Get reference to main run loop.
CFRunLoopRef cfrl = CFRunLoopGetCurrent();
// Schedule socket with run loop, by roundabout means.
CFRunLoopSourceRef source4 = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0);
CFRunLoopAddSource(cfrl, source4, kCFRunLoopCommonModes);
CFRelease(source4);
// Socket made
return YES;
}
Runloop 일정
예, 4 개 스트림은 runloop에서 예정된 모든 코드는 위의 첫 번째 업데이트에서 게시 한 것과 동일합니다.
Runloop 차단 : 내가 동기화, 다중 스레드, NSLocks 등 공상 아무것도 아니에요
. 콘솔에 무언가를 인쇄하기 위해 버튼 동작을 설정하면,이 동작은 전반적으로 작동합니다. runloop은 정상적으로 실행되는 것처럼 보입니다.
업데이트 4, 스트림 포트? 내가 스트림 자신의 포트에 매달려 있었다,하지만 놀랍게도, nTest
는 항상 null이라고 가정했다
NSNumber *nTest = [self.streamIn propertyForKey:NSStreamSOCKSProxyPortKey]; // always null!
:
노아의 디버깅 제안
더 스트림의 속성을 검사하는 나에게 아이디어를 주었다. 그것은 내 애플 리케이션에서 null입니다. 문제를 지적하는 것처럼 보이지만, 이 인 튜토리얼 앱에서도 null입니다. 일단 스트림이 만들어지면 포트 할당에 매달릴 필요가 없으면 포트 속성의 목적은 무엇입니까?아마도 port 속성에 직접 액세스 할 수 없습니까? 그러나 nTest
도 다음에 항상 널 :
NSDictionary *dTest = [theInStream propertyForKey:NSStreamSOCKSProxyConfigurationKey];
NSNumber *nTest = [dTest valueForKey:NSStreamSOCKSProxyPortKey];
NSLog(@"\tInstream port is %@.", nTest); // (null)
nTest = [dTest valueForKey:NSStreamSOCKSProxyPortKey];
NSLog(@"\tOutstream port is %@.", nTest); // (null)
당신이'-hasBytesAvailable'와'- 읽기를 호출 해봤'직접? – paulmelnikow
iPhone에서 [self.streamIn hasBytesAvailable]을 호출하면 Mac이 바이트를 쓴다는 것을 Mac 응용 프로그램 로그에서 확인한 후에도 테스트 버튼 액션을 통해 * 호출한다고해도 NO가 반환됩니다. 우수한 디버깅 조언, 아니 반환과 함께 나는 다음에 무엇을해야할지 모르겠다. – Wienke
어떤 소켓 옵션을 설정 했습니까? 이러한 스트림을 사용하여 소켓을 어떻게 만들었습니까? 모든 스트림이 예정대로 운영되고 있습니까? 문제의 실행 루프가 실제로 실행되고 있습니까 (예 : 아무 곳이나 차단하지 않습니까?) – alastair