mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 07:36:10 -04:00
[Nearby] Optimize NWFramework socket reads and writes for performance and memory. III
PiperOrigin-RevId: 894930585
This commit is contained in:
committed by
Copybara-Service
parent
1bc6346601
commit
b382cdb022
@@ -26,4 +26,5 @@ typedef NS_ERROR_ENUM(GNCNWFrameworkErrorDomain, GNCNWFrameworkError){
|
||||
GNCNWFrameworkErrorUnknown,
|
||||
GNCNWFrameworkErrorTimedOut,
|
||||
GNCNWFrameworkErrorDuplicateDiscovererForServiceType,
|
||||
GNCNWFrameworkErrorNotConnected,
|
||||
};
|
||||
|
||||
@@ -75,6 +75,17 @@
|
||||
*/
|
||||
- (BOOL)write:(NSData *)data error:(NSError **_Nullable)error;
|
||||
|
||||
/**
|
||||
* Writes raw bytes to the connection.
|
||||
*
|
||||
* @param bytes The buffer to write.
|
||||
* @param length The number of bytes to write.
|
||||
* @param error Error that will be populated on failure.
|
||||
*/
|
||||
- (BOOL)writeBytes:(const void *)bytes
|
||||
length:(NSUInteger)length
|
||||
error:(NSError **_Nullable)error;
|
||||
|
||||
/**
|
||||
* Gracefully closes the connection to remote endpoint.
|
||||
*
|
||||
|
||||
@@ -92,7 +92,7 @@ static const NSTimeInterval kConnectionWriteTimeout = 5.0; // 5 seconds timeout
|
||||
if (!self.connection) {
|
||||
if (error) {
|
||||
*error = [NSError errorWithDomain:GNCNWFrameworkErrorDomain
|
||||
code:GNCNWFrameworkErrorUnknown
|
||||
code:GNCNWFrameworkErrorNotConnected
|
||||
userInfo:nil];
|
||||
}
|
||||
return std::nullopt;
|
||||
@@ -185,6 +185,50 @@ static const NSTimeInterval kConnectionWriteTimeout = 5.0; // 5 seconds timeout
|
||||
return signaled && blockSuccess;
|
||||
}
|
||||
|
||||
- (BOOL)writeBytes:(const void *)bytes length:(NSUInteger)length error:(NSError **)error {
|
||||
if (!self.connection) {
|
||||
if (error) {
|
||||
*error = [NSError errorWithDomain:GNCNWFrameworkErrorDomain
|
||||
code:GNCNWFrameworkErrorNotConnected
|
||||
userInfo:nil];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
__block NSError *blockError = nil;
|
||||
|
||||
// OPTIMIZATION: Use DISPATCH_DATA_DESTRUCTOR_DEFAULT to perform a
|
||||
// single copy into a GCD-managed buffer. No NSData required.
|
||||
// TODO: edwinwu - Investigate to see if it is worth to make it zero-copy by replacing
|
||||
// DISPATCH_DATA_DESTRUCTOR_DEFAULT with a custom empty destructor:
|
||||
// dispatch_data_t dispatchData = dispatch_data_create(bytes, length, nil, ^{
|
||||
// // Zero-copy: ownership remains with the caller.
|
||||
// });
|
||||
dispatch_data_t dispatchData =
|
||||
dispatch_data_create(bytes, length, nil, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
|
||||
|
||||
[self.connection sendData:dispatchData
|
||||
context:NW_CONNECTION_DEFAULT_MESSAGE_CONTEXT
|
||||
isComplete:NO
|
||||
completionHandler:^(nw_error_t _Nullable sendError) {
|
||||
if (sendError) {
|
||||
blockError = (__bridge_transfer NSError *)nw_error_copy_cf_error(sendError);
|
||||
}
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
}];
|
||||
|
||||
// Wait until signaled or the 5-second timeout passes
|
||||
intptr_t waitResult = dispatch_semaphore_wait(
|
||||
semaphore,
|
||||
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kConnectionWriteTimeout * NSEC_PER_SEC)));
|
||||
if (error != nil) {
|
||||
*error = blockError;
|
||||
}
|
||||
return (waitResult == 0) && (blockError == nil);
|
||||
}
|
||||
|
||||
- (void)close {
|
||||
[_connection cancel];
|
||||
_connection = nil;
|
||||
|
||||
+23
@@ -132,6 +132,28 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
XCTAssertFalse(result);
|
||||
}
|
||||
|
||||
- (void)testWriteBytes_Success {
|
||||
NSError *error = nil;
|
||||
NSString *testString = @"testData";
|
||||
NSData *testData = [testString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
BOOL result = [_socket writeBytes:testData.bytes length:testData.length error:&error];
|
||||
|
||||
XCTAssertTrue(result);
|
||||
XCTAssertNil(error);
|
||||
}
|
||||
|
||||
- (void)testWriteBytes_Error {
|
||||
NSError *error = nil;
|
||||
NSString *testString = @"testData";
|
||||
NSData *testData = [testString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
_fakeConnection.simulateSendFailure = YES;
|
||||
|
||||
BOOL result = [_socket writeBytes:testData.bytes length:testData.length error:&error];
|
||||
|
||||
XCTAssertFalse(result);
|
||||
}
|
||||
|
||||
- (void)testClose {
|
||||
XCTAssertFalse(_fakeConnection.cancelCalled);
|
||||
[_socket close];
|
||||
@@ -140,6 +162,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
NSError *error = nil;
|
||||
XCTAssertNil([_socket readMaxLength:10 error:&error]);
|
||||
XCTAssertFalse([_socket write:[NSData data] error:&error]);
|
||||
XCTAssertFalse([_socket writeBytes:"test" length:4 error:&error]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user