UNIX域套接字处理您的插座一个很好的教程是一个难啃的劫掠。对于那些还没有这样做,并有兴趣然后去做的人。之后会有成就感。然而,即使从Beej和这个网站的信息,甚至从苹果有很多断开连接。我在这里介绍了一个可以启用ARC的Cocoa的结论性示例。我在等待Sidnicious和他的样品,但从未看到任何东西,所以我决定自己解决这个问题。
什么我这里有三个接口,一个标题和.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
第二节(服务器)
注:服务器雷乌斯es连接到自己的客户端的客户端代码。 面向对象编程,一定要喜欢它!
#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中实例化这些(未经测试)。
希望这可以帮助那里的人作为一个完整的工作示例。 Arvin
你能分享你的代码吗? – 2012-01-25 11:53:19