【问题标题】:UNIX Domain Sockets and CocoaUNIX 域套接字和 Cocoa
【发布时间】:2010-11-02 15:01:12
【问题描述】:

我想在 Cocoa 应用程序中使用 UNIX 域套接字实现 IPC,但我没有这方面的经验。我找到了 Apple 的 CFLocalServer 示例项目,但它是用 C 语言编写的,看起来相当复杂(是的,我已经阅读了大部分内容)。

CFLocalServer 中演示的技术是否仍然是最先进的,或者有没有办法在 Objective-C 中使用 Cocoa/Foundation 实现 UNIX 域套接字?

我正在使用NSSocketPorts 和NSFileHandles(它们提供了健康的抽象量,这对这个项目非常有用)并在Mike Bean's Networking in Cocoa 中找到了一些非常相关的代码,但还没有能够让它全部工作。

以前有人做过吗?

【问题讨论】:

    标签: cocoa macos sockets ipc


    【解决方案1】:

    为什么不试试 POSIX 命名管道。 Mac OSX 是一个基于 BSD 的 POSIX-ish 操作系统,所以它应该是直截了当的:

    http://www.ecst.csuchico.edu/~beej/guide/ipc/fifos.html

    【讨论】:

    • 感谢您的回答!据我所知,命名管道有两端——对于这个项目,我需要一个服务器、多个客户端的关系。
    【解决方案2】:

    最后,我确实使用了 UNIX 域套接字,它们工作得很好。我已经启动为我的服务器设置了套接字(但确实编写了代码,成功地自己创建了它),并让客户端连接到它。

    我学到的东西:

    • 你可以将连接的两端包裹在 NSFileHandle 中

    • 您确实需要在客户端使用connect() 来创建到套接字的连接

    • 您应该让客户端和服务器都忽略 SIGPIPE

    • 如果你用零长度数据被回调,这意味着套接字另一端的东西已经断开(即服务器/客户端退出)。在这种情况下,请确保关闭并释放套接字的末端——不要尝试再次从中读取数据,或者只是获得另一个零长度的读取回调(永远)

    • 您负责对通过套接字发送的消息进行定界和组合(在一端发送的单个消息可能会在另一端发送到多个消息,或者可能合并多个消息)

    我很乐意分享或发布代码,只是没有时间清理它以供公众使用。如果有人有兴趣,请告诉我。

    【讨论】:

    • @ParagBafna 我可能需要几天/几周的时间才能把它放在一起。我会尽快做的。
    • 如果另一端挂断,您应该能够重新连接套接字。我认为您不需要从头开始重新创建它。明天测试。
    【解决方案3】:

    http://macdevcenter.com/pub/a/mac/2003/05/13/cocoa.html 是使用NSFileHandle 处理套接字的好教程

    【讨论】:

      【解决方案4】:

      UNIX 域套接字是一个难以抓住的难题。对于没有这样做的人,并且有兴趣,那就去吧。之后会有成就感。然而,即使有来自 Beej 和这个网站甚至来自 Apple 的信息,也有很多断开连接。我在这里展示了一个启用了 ARC 的 Cocoa 的结论性示例。我一直在等待 Sidnious 和他的样本,但什么都没看到,所以我决定自己解决这个问题。

      我这里有一个带有三个接口的头文件和 .m 实现文件。 一个超类接口,然后是继承的服务器和客户端接口。 我做了一些有限的测试,它似乎工作得很好。但是,一直在寻找改进,所以请告诉我...

      头文件:

      typedef enum _CommSocketServerStatus {
      
          CommSocketServerStatusUnknown       = 0,
          CommSocketServerStatusRunning       = 1,
          CommSocketServerStatusStopped       = 2,
          CommSocketServerStatusStarting      = 3,
          CommSocketServerStatusStopping      = 4
      
      } CommSocketServerStatus;
      
      typedef enum _CommSocketClientStatus {
      
          CommSocketClientStatusUnknown       = 0,
          CommSocketClientStatusLinked        = 1,
          CommSocketClientStatusDisconnected  = 2,
          CommSocketClientStatusLinking       = 3,
          CommSocketClientStatusDisconnecting = 4
      
      } CommSocketClientStatus;
      
      @class CommSocketServer, CommSocketClient;
      
      @protocol CommSocketServerDelegate <NSObject>
      @optional
      - (void) handleSocketServerStopped:(CommSocketServer *)server;
      - (void) handleSocketServerMsgURL:(NSURL *)aURL          fromClient:(CommSocketClient *)client;
      - (void) handleSocketServerMsgString:(NSString *)aString fromClient:(CommSocketClient *)client;
      - (void) handleSocketServerMsgNumber:(NSNumber *)aNumber fromClient:(CommSocketClient *)client;
      - (void) handleSocketServerMsgArray:(NSArray *)aArray    fromClient:(CommSocketClient *)client;
      - (void) handleSocketServerMsgDict:(NSDictionary *)aDict fromClient:(CommSocketClient *)client;
      @end
      
      @protocol CommSocketClientDelegate <NSObject>
      @optional
      - (void) handleSocketClientDisconnect:(CommSocketClient *)client;
      - (void) handleSocketClientMsgURL:(NSURL *)aURL          client:(CommSocketClient *)client;
      - (void) handleSocketClientMsgString:(NSString *)aString client:(CommSocketClient *)client;
      - (void) handleSocketClientMsgNumber:(NSNumber *)aNumber client:(CommSocketClient *)client;
      - (void) handleSocketClientMsgArray:(NSArray *)aArray    client:(CommSocketClient *)client;
      - (void) handleSocketClientMsgDict:(NSDictionary *)aDict client:(CommSocketClient *)client;
      @end
      
      @interface CommSocket : NSObject
      @property (readonly, nonatomic, getter=isSockRefValid) BOOL sockRefValid;
      @property (readonly, nonatomic, getter=isSockConnected) BOOL sockConnected;
      @property (readonly, nonatomic) CFSocketRef sockRef;
      @property (readonly, strong, nonatomic) NSURL    *sockURL;
      @property (readonly, strong, nonatomic) NSData   *sockAddress;
      @property (readonly, strong, nonatomic) NSString *sockLastError;
      @end
      
      @interface CommSocketServer : CommSocket <CommSocketClientDelegate> { id <CommSocketServerDelegate> delegate; }
      @property (readwrite, strong, nonatomic) id delegate;
      @property (readonly,  strong, nonatomic) NSSet *sockClients;
      @property (readonly, nonatomic) CommSocketServerStatus sockStatus;
      @property (readonly, nonatomic) BOOL startServer;
      @property (readonly, nonatomic) BOOL stopServer;
      - (id) initWithSocketURL:(NSURL *)socketURL;
      + (id) initAndStartServer:(NSURL *)socketURL;
      - (void) addConnectedClient:(CFSocketNativeHandle)handle;
      
      - (void) messageClientsURL:(NSURL *)aURL;
      - (void) messageClientsString:(NSString *)aString;
      - (void) messageClientsNumber:(NSNumber *)aNumber;
      - (void) messageClientsArray:(NSArray *)aArray;
      - (void) messageClientsDict:(NSDictionary *)aDict;
      
      @end
      
      @interface CommSocketClient : CommSocket { id <CommSocketClientDelegate> delegate; }
      @property (readwrite, strong, nonatomic) id delegate;
      @property (readonly, nonatomic) CommSocketClientStatus sockStatus;
      @property (readonly, nonatomic) CFRunLoopSourceRef sockRLSourceRef;
      @property (readonly, nonatomic) BOOL startClient;
      @property (readonly, nonatomic) BOOL stopClient;
      - (id) initWithSocketURL:(NSURL *)socketURL;
      - (id) initWithSocket:(CFSocketNativeHandle)handle;
      + (id) initAndStartClient:(NSURL *)socketURL;
      + (id) initWithSocket:(CFSocketNativeHandle)handle;
      
      - (void) messageReceived:(NSData *)data;
      - (BOOL) messageURL:(NSURL *)aURL;
      - (BOOL) messageString:(NSString *)aString;
      - (BOOL) messageNumber:(NSNumber *)aNumber;
      - (BOOL) messageArray:(NSArray *)aArray;
      - (BOOL) messageDict:(NSDictionary *)aDict;
      
      @end
      

      实现文件:(我将分三个部分介绍)

      ​​>

      第一节(超类)

      #import "CommSocket.h"
      
      #import <sys/un.h>
      #import <sys/socket.h> 
      
      #pragma mark Socket Superclass:
      
      @interface CommSocket ()
      @property (readwrite, nonatomic) CFSocketRef sockRef;
      @property (readwrite, strong, nonatomic) NSURL *sockURL;
      @end
      
      @implementation CommSocket
      @synthesize sockConnected;
      @synthesize sockRef, sockURL;
      
      - (BOOL) isSockRefValid {
          if ( self.sockRef == nil ) return NO;
          return (BOOL)CFSocketIsValid( self.sockRef );
      }
      
      - (NSData *) sockAddress {
      
          struct sockaddr_un address;
          address.sun_family = AF_UNIX;
          strcpy( address.sun_path, [[self.sockURL path] fileSystemRepresentation] );
          address.sun_len = SUN_LEN( &address );
          return [NSData dataWithBytes:&address length:sizeof(struct sockaddr_un)];
      }
      
      - (NSString *) sockLastError {
          return [NSString stringWithFormat:@"%s (%d)", strerror( errno ), errno ];
      }
      
      @end
      

      第二部分(服务器)

      注意:服务器为连接到自身的客户端重复使用客户端代码。 OO-programming,爱不释手!

      #pragma mark - Socket: Server
      #pragma mark -
      
      @interface CommSocketServer ()
      @property (readonly, nonatomic) BOOL startServerCleanup;
      @property (readwrite, nonatomic) CommSocketServerStatus sockStatus;
      @property (readwrite,  strong, nonatomic) NSSet *sockClients;
      static void SocketServerCallback (CFSocketRef sock, CFSocketCallBackType type, CFDataRef address, const void *data, void *info);
      @end
      
      #pragma mark - Server Implementation:
      
      @implementation CommSocketServer
      
      @synthesize delegate;
      @synthesize sockStatus;
      @synthesize sockClients;
      
      #pragma mark - Helper Methods:
      
      - (BOOL) socketServerCreate {
      
          if ( self.sockRef != nil ) return NO;
          CFSocketNativeHandle sock = socket( AF_UNIX, SOCK_STREAM, 0 );
          CFSocketContext context = { 0, (__bridge void *)self, nil, nil, nil };
          CFSocketRef refSock = CFSocketCreateWithNative( nil, sock, kCFSocketAcceptCallBack, SocketServerCallback, &context );
      
          if ( refSock == nil ) return NO;
      
          int opt = 1;
          setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt));
          setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&opt, sizeof(opt));
      
          self.sockRef = refSock;
          CFRelease( refSock );
      
          return YES;
      }
      
      - (BOOL) socketServerBind {
          if ( self.sockRef == nil ) return NO;
          unlink( [[self.sockURL path] fileSystemRepresentation] );
          if ( CFSocketSetAddress(self.sockRef, (__bridge CFDataRef)self.sockAddress) != kCFSocketSuccess ) return NO;
          return YES;
      }
      
      #pragma mark - Connected Clients:
      
      - (void) disconnectClients {
      
      
          for ( CommSocketClient *client in self.sockClients )
              [client stopClient];
      
          self.sockClients = [NSSet set];
      }
      
      - (void) disconnectClient:(CommSocketClient *)client {
      
          @synchronized( self ) {
              NSMutableSet *clients = [NSMutableSet setWithSet:self.sockClients];
      
              if ( [clients containsObject:client] ) {
      
                  if ( client.isSockRefValid ) [client stopClient];
                  [clients removeObject:client];
                  self.sockClients = clients;
          } }
      }
      
      - (void) addConnectedClient:(CFSocketNativeHandle)handle {
      
          @synchronized( self ) {
              CommSocketClient *client = [CommSocketClient initWithSocket:handle];
              client.delegate = self;
              NSMutableSet *clients = [NSMutableSet setWithSet:self.sockClients];
      
              if ( client.isSockConnected ) {
                  [clients addObject:client];
                  self.sockClients = clients;
          } }
      }
      
      #pragma mark - Connected Client Protocols:
      
      - (void) handleSocketClientDisconnect:(CommSocketClient *)client {
      
          [self disconnectClient:client];
      }
      
      - (void) handleSocketClientMsgURL:(NSURL *)aURL client:(CommSocketClient *)client {
      
          if ( [self.delegate respondsToSelector:@selector(handleSocketServerMsgURL:server:fromClient:)] )
              [self.delegate handleSocketServerMsgURL:aURL fromClient:client];
      }
      
      - (void) handleSocketClientMsgString:(NSString *)aString client:(CommSocketClient *)client {
      
          if ( [self.delegate respondsToSelector:@selector(handleSocketServerMsgString:fromClient:)] )
              [self.delegate handleSocketServerMsgString:aString fromClient:client];
      }
      
      - (void) handleSocketClientMsgNumber:(NSNumber *)aNumber client:(CommSocketClient *)client {
      
          if ( [self.delegate respondsToSelector:@selector(handleSocketServerMsgNumber:fromClient:)] )
              [self.delegate handleSocketClientMsgNumber:aNumber client:client];
      }
      
      - (void) handleSocketClientMsgArray:(NSArray *)aArray client:(CommSocketClient *)client {
      
          if ( [self.delegate respondsToSelector:@selector(handleSocketServerMsgArray:fromClient:)] )
              [self.delegate handleSocketServerMsgArray:aArray fromClient:client];
      }
      
      - (void) handleSocketClientMsgDict:(NSDictionary *)aDict client:(CommSocketClient *)client {
      
          if ( [self.delegate respondsToSelector:@selector(handleSocketServerMsgDict:fromClient:)] )
              [self.delegate handleSocketServerMsgDict:aDict fromClient:client];
      }
      
      #pragma mark - Connected Client Messaging:
      
      - (void) messageClientsURL:(NSURL *)aURL {
          for ( CommSocketClient *client in self.sockClients)
              [client messageURL:aURL];
      }
      
      - (void) messageClientsString:(NSString *)aString {
          for ( CommSocketClient *client in self.sockClients)
              [client messageString:aString];
      }
      
      - (void) messageClientsNumber:(NSNumber *)aNumber {
          for ( CommSocketClient *client in self.sockClients)
              [client messageNumber:aNumber];
      }
      
      - (void) messageClientsArray:(NSArray *)aArray {
          for ( CommSocketClient *client in self.sockClients)
              [client messageArray:aArray];
      }
      
      - (void) messageClientsDict:(NSDictionary *)aDict {
          for ( CommSocketClient *client in self.sockClients)
              [client messageDict:aDict];
      }
      
      #pragma mark - Start / Stop Server:
      
      - (BOOL) startServerCleanup { [self stopServer]; return NO; }
      
      - (BOOL) startServer {
      
          if ( self.sockStatus == CommSocketServerStatusRunning ) return YES;
          self.sockStatus = CommSocketServerStatusStarting;
      
          if ( ![self socketServerCreate] ) return self.startServerCleanup;
          if ( ![self socketServerBind]   ) return self.startServerCleanup;
      
          CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource( kCFAllocatorDefault, self.sockRef, 0 );
          CFRunLoopAddSource( CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes );
          CFRelease( sourceRef );
      
          self.sockStatus = CommSocketServerStatusRunning;
          return YES;
      }
      
      - (BOOL) stopServer {
      
          self.sockStatus = CommSocketServerStatusStopping;
      
          [self disconnectClients];
      
          if ( self.sockRef != nil ) {
      
              CFSocketInvalidate(self.sockRef);
              self.sockRef = nil;
          }
      
          unlink( [[self.sockURL path] fileSystemRepresentation] );
      
          if ( [self.delegate respondsToSelector:@selector(handleSocketServerStopped:)] )
              [self.delegate handleSocketServerStopped:self];
      
          self.sockStatus = CommSocketServerStatusStopped;
          return YES;
      }
      
      #pragma mark - Server Validation:
      
      - (BOOL) isSockConnected {
      
          if ( self.sockStatus == CommSocketServerStatusRunning )
              return self.isSockRefValid;
      
          return NO;
      }
      
      #pragma mark - Initialization:
      
      + (id) initAndStartServer:(NSURL *)socketURL {
      
          CommSocketServer *server = [[CommSocketServer alloc] initWithSocketURL:socketURL];
          [server startServer];
          return server;
      }
      
      - (id) initWithSocketURL:(NSURL *)socketURL {
      
          if ( (self = [super init]) ) {
      
              self.sockURL     = socketURL;
              self.sockStatus  = CommSocketServerStatusStopped;
              self.sockClients = [NSSet set];
      
          } return self;
      }
      
      - (void) dealloc { [self stopServer]; }
      
      #pragma mark - Server Callback:
      
      static void SocketServerCallback (CFSocketRef sock, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
      
          CommSocketServer *server = (__bridge CommSocketServer *)info;
      
          if ( kCFSocketAcceptCallBack == type ) {
              CFSocketNativeHandle handle = *(CFSocketNativeHandle *)data;
              [server addConnectedClient:handle];
          }
      }
      
      @end
      

      第三部分(客户)

      #pragma mark - Socket: Client
      #pragma mark -
      
      @interface CommSocketClient ()
      @property (readonly, nonatomic) BOOL startClientCleanup;
      @property (readwrite, nonatomic) CommSocketClientStatus sockStatus;
      @property (readwrite, nonatomic) CFRunLoopSourceRef sockRLSourceRef;
      static void SocketClientCallback (CFSocketRef sock, CFSocketCallBackType type, CFDataRef address, const void *data, void *info);
      @end
      
      #pragma mark - Client Implementation:
      
      @implementation CommSocketClient
      
      static NSTimeInterval const kCommSocketClientTimeout = 5.0;
      
      @synthesize delegate;
      @synthesize sockStatus;
      @synthesize sockRLSourceRef;
      
      #pragma mark - Helper Methods:
      
      - (BOOL) socketClientCreate:(CFSocketNativeHandle)sock {
      
          if ( self.sockRef != nil ) return NO;
          CFSocketContext context = { 0, (__bridge void *)self, nil, nil, nil };
          CFSocketCallBackType types = kCFSocketDataCallBack;
          CFSocketRef refSock = CFSocketCreateWithNative( nil, sock, types, SocketClientCallback, &context );
      
          if ( refSock == nil ) return NO;
      
          int opt = 1;
          setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&opt, sizeof(opt));
      
          self.sockRef = refSock;
          CFRelease( refSock );
      
          return YES;
      }
      
      - (BOOL) socketClientBind {
          if ( self.sockRef == nil ) return NO;
          if ( CFSocketConnectToAddress(self.sockRef, 
                                        (__bridge CFDataRef)self.sockAddress, 
                                        (CFTimeInterval)kCommSocketClientTimeout) != kCFSocketSuccess ) return NO;
          return YES;
      }
      
      #pragma mark - Client Messaging:
      
      - (void) messageReceived:(NSData *)data {
      
          id msg = [NSKeyedUnarchiver unarchiveObjectWithData:data];
      
          if ( [msg isKindOfClass:[NSURL class]] ) {
      
              if ( [self.delegate respondsToSelector:@selector(handleSocketClientMsgURL:client:)] )
                  [self.delegate handleSocketClientMsgURL:(NSURL *)msg client:self];
          }
      
          else if ( [msg isKindOfClass:[NSString class]] ) {
      
              if ( [self.delegate respondsToSelector:@selector(handleSocketClientMsgString:client:)] )
                  [self.delegate handleSocketClientMsgString:(NSString *)msg client:self];
          }
      
          else if ( [msg isKindOfClass:[NSNumber class]] ) {
      
              if ( [self.delegate respondsToSelector:@selector(handleSocketClientMsgNumber:client:)] )
                  [self.delegate handleSocketClientMsgNumber:(NSNumber *)msg client:self];
          }
      
          else if ( [msg isKindOfClass:[NSArray class]] ) {
      
              if ( [self.delegate respondsToSelector:@selector(handleSocketClientMsgArray:client:)] )
                  [self.delegate handleSocketClientMsgArray:(NSArray *)msg client:self];
          }
      
          else if ( [msg isKindOfClass:[NSDictionary class]] ) {
      
              if ( [self.delegate respondsToSelector:@selector(handleSocketClientMsgDict:client:)] )
                  [self.delegate handleSocketClientMsgDict:(NSDictionary *)msg client:self];
          }
      }
      
      - (BOOL) messageData:(NSData *)data {
      
          if ( self.isSockConnected ) {
      
              if ( kCFSocketSuccess == CFSocketSendData(self.sockRef, 
                                                        nil, 
                                                        (__bridge CFDataRef)data, 
                                                        kCommSocketClientTimeout) )
                  return YES;
      
          } return NO;
      }
      
      - (BOOL) messageURL:(NSURL *)aURL          { return [self messageData:[NSKeyedArchiver archivedDataWithRootObject:aURL]];    }
      - (BOOL) messageString:(NSString *)aString { return [self messageData:[NSKeyedArchiver archivedDataWithRootObject:aString]]; }
      - (BOOL) messageNumber:(NSNumber *)aNumber { return [self messageData:[NSKeyedArchiver archivedDataWithRootObject:aNumber]]; }
      - (BOOL) messageArray:(NSArray *)aArray    { return [self messageData:[NSKeyedArchiver archivedDataWithRootObject:aArray]];  }
      - (BOOL) messageDict:(NSDictionary *)aDict { return [self messageData:[NSKeyedArchiver archivedDataWithRootObject:aDict]];   }
      
      #pragma mark - Start / Stop Client:
      
      - (BOOL) startClientCleanup { [self stopClient]; return NO; }
      
      - (BOOL) startClient {
      
          if ( self.sockStatus == CommSocketClientStatusLinked ) return YES;
          self.sockStatus = CommSocketClientStatusLinking;
      
          CFSocketNativeHandle sock = socket( AF_UNIX, SOCK_STREAM, 0 );
          if ( ![self socketClientCreate:sock] ) return self.startClientCleanup;
          if ( ![self socketClientBind]        ) return self.startClientCleanup;
      
          CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource( kCFAllocatorDefault, self.sockRef, 0 );
          CFRunLoopAddSource( CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes );
      
          self.sockRLSourceRef = sourceRef;
          CFRelease( sourceRef );
      
          self.sockStatus = CommSocketClientStatusLinked;
          return YES;
      }
      
      - (BOOL) stopClient {
      
          self.sockStatus = CommSocketClientStatusDisconnecting;
      
          if ( self.sockRef != nil ) {
      
              if ( self.sockRLSourceRef != nil ) {
      
                  CFRunLoopSourceInvalidate( self.sockRLSourceRef );
                  self.sockRLSourceRef = nil;
              }
      
              CFSocketInvalidate(self.sockRef);
              self.sockRef = nil;
          }
      
          if ( [self.delegate respondsToSelector:@selector(handleSocketClientDisconnect:)] )
              [self.delegate handleSocketClientDisconnect:self];
      
          self.sockStatus = CommSocketClientStatusDisconnected;
      
          return YES;
      }
      
      #pragma mark - Client Validation:
      
      - (BOOL) isSockConnected {
      
          if ( self.sockStatus == CommSocketClientStatusLinked )
              return self.isSockRefValid;
      
          return NO;
      }
      
      #pragma mark - Initialization:
      
      + (id) initAndStartClient:(NSURL *)socketURL {
      
          CommSocketClient *client = [[CommSocketClient alloc] initWithSocketURL:socketURL];
          [client startClient];
          return client;
      }
      
      + (id) initWithSocket:(CFSocketNativeHandle)handle {
      
          CommSocketClient *client = [[CommSocketClient alloc] initWithSocket:handle];
          return client;
      }
      
      - (id) initWithSocketURL:(NSURL *)socketURL {
      
          if ( (self = [super init]) ) {
      
              self.sockURL    = socketURL;
              self.sockStatus = CommSocketClientStatusDisconnected;
      
          } return self;
      }
      
      - (id) initWithSocket:(CFSocketNativeHandle)handle {
      
          if ( (self = [super init]) ) {
      
              self.sockStatus = CommSocketClientStatusLinking;
      
              if ( ![self socketClientCreate:handle] ) [self startClientCleanup];
      
              else {
      
                  CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource( kCFAllocatorDefault, self.sockRef, 0 );
                  CFRunLoopAddSource( CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes );
      
                  self.sockRLSourceRef = sourceRef;
                  CFRelease( sourceRef );
      
                  self.sockStatus = CommSocketClientStatusLinked;
              }
      
          } return self;
      }
      
      - (void) dealloc { [self stopClient]; }
      
      #pragma mark - Client Callback:
      
      static void SocketClientCallback (CFSocketRef sock, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
      
          CommSocketClient *client = (__bridge CommSocketClient *)info;
      
          if ( kCFSocketDataCallBack == type ) {
      
              NSData *objData = (__bridge NSData *)data;
      
              if ( [objData length] == 0 )
                  [client stopClient];
      
              else
                  [client messageReceived:objData];
          }
      }
      
      @end
      

      好的,就是这样,它应该在不同的进程中工作。

      只需使用它来创建一个服务器,其中包含放置套接字文件的路径。

      • (id) initAndStartServer:(NSURL *)socketURL;

      同样,使用它来创建客户端连接

      • (id) initAndStartClient:(NSURL *)socketURL;

      使用我包含的委托方法,其余部分应该很简单。 最后,保持 url 路径小(没有为此添加任何真正的检查) 你可以在一个单独的 NSOperationQueue 中实例化它们(虽然未经测试)。

      希望这可以作为一个完整的工作样本对那里的人有所帮助。 阿尔文

      【讨论】:

      • 太棒了!!!非常感谢这个干净的代码。这正是官方文档中缺少的内容。
      • 如果路径长度超过 103 个字符,您的 -sockAddress 方法似乎将 strcpy() 超出结构的末尾。我猜想解决这个问题的方法是创建一个大的 NSMutableData,复制路径,然后将数据调整为SUN_LEN(&amp;address)。在这种情况下,我不清楚sun_len 字段应该是什么;它受到unsigned char 大小的限制。
      • strcpy 这里是 defo 不安全的。似乎套接字路径必须短于 104 字节,这就是限制。从这段代码中学习,感谢?分享。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-02
      • 1970-01-01
      • 2015-07-20
      • 2014-07-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多