CocoaAsyncSocket 的读写委托不是触发和代码组织

Posted

技术标签:

【中文标题】CocoaAsyncSocket 的读写委托不是触发和代码组织【英文标题】:CocoaAsyncSocket's read and write delegates are not firing & code organization 【发布时间】:2011-06-17 08:03:55 【问题描述】:

我正在尝试使用 cocoaasyncsocket 库附带的 echo 服务器示例的修改版本来执行以下操作:

1) 打开与充当服务器的 python 脚本的连接 2) 发送数据 // 有效,但委托不触发 3) 接收数据 // 委托不触发 4) disconnect // 没有断开,显然还在我的线程中

目前我在 didFinishLaunchingWithOptions 委托中打开一个连接,然后尝试在 didConnectToHost 委托中发送数据。然后我尝试读取从客户端返回的数据,然后断开连接。

我能够打开连接并发送数据(服务器验证为已接收),但 didWriteDataWithTag 委托永远不会触发。但是,服务器接收数据。然后服务器会返回一些数据,但 didReadData 也不会触发。

除了读/写委托没有触发之外,我组织代码的方式似乎不正确,但我不确定这在事件驱动系统中的外观与运行循环相比如何(我是事件驱动的东西+网络的新手)。如果我有一系列动作,其各自的完成是由他们的代表触发的,那么代表是否应该共享某种消息 - 即我们收到“xxx”消息,写回“yyy”?我希望有一个功能来管理所有这些。有这样做的规范方法吗?

IPhoneConnectTestAppDelegate.m (sn-ps)

- (void)localConnect 
    NSError *error = nil;
    if (![asyncSocket connectToHost:@"localhost" onPort:5000 error:&error]) 
        DDLogError(@"Error connecting: %@", error);
    


- (void)disconnect 
    [asyncSocket setDelegate:nil];
    [asyncSocket disconnect];
    [asyncSocket release];


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
    // Setup our socket (GCDAsyncSocket).
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];

    [self localConnect];

    // Add the view controller's view to the window and display.
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];



- (void)onSocket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag 
    NSString *output = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
    NSLog(@"didReadData: %@", output);



- (void)onSocket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag 
    NSLog(@"didWriteDataWithTag");


- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port 
    NSLog(@"socket:%p didConnectToHost:%@ port:%hu", sock, host, port);
    if(port == 5000)
    
        NSString *msg = @"q";
        NSData *dataOut = [msg dataUsingEncoding:NSASCIIStringEncoding];
        [asyncSocket writeData:dataOut withTimeout:-1 tag:0];
        [asyncSocket readDataWithTimeout:-1 tag:0];
        [self disconnect];
    

tcpserver.py

# TCP server example
import socket, time
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("", 5000))
server_socket.listen(5)

print "TCPServer Waiting for client on port 5000"

while 1:
    client_socket, address = server_socket.accept()
    print "I got a connection from ", address
    while 1:
        data = client_socket.recv(512)
        print "Data from client",data

        time.sleep(2)
        data = "xxx"
        print "Sending data to client",data
        client_socket.send (data)
        break;

【问题讨论】:

对于 BSD 套接字周围的简单套接字包装器并将这些操作放在工作线程上,我的麻烦要少得多。 【参考方案1】:

我知道这是一个已经被接受的答案的老问题,但是为了澄清那些发现这个线程正在寻找东西的人,委托方法没有被调用的原因是因为 GCDAsynchSocket 以 socket: 而不是onsocket:即:

- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag

变成:

- (void) socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag

【讨论】:

【参考方案2】:

朋友的朋友帮我解决了这个问题!我们无法让 GCDAsyncSocket 正常工作(连接和写入,但不能读取)。然而,AsyncSocket 在所有 3 个方面都起作用,并且所有委托都正常工作。

#import "AsyncSocket.h"
#import "tcp_clientViewController.h"

@implementation tcp_clientViewController

@synthesize socket;



-(IBAction)connect:(id)sender  
    NSLog(@"(IBAction)connect");
    NSError *error = nil;
    if (![socket connectToHost:@"localhost" onPort:5000 error:&error])
        NSLog(@"Error connecting: %@", error);
    


-(IBAction)send:(id)sender 
    NSLog(@"(IBAction)send");


    char bytes[] = "abcd\r\n";
    NSData* data = [[NSData alloc] initWithBytes:bytes length:sizeof(bytes)];

    //NSString *msg = @"xxxxx\r\n";
    //NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];


    [socket writeData:data withTimeout:-1 tag:0];
    //NSData *data = [asyncSocket readDataWithTimeout:-1 tag:0];
    [data release];

    [socket readDataToData:[AsyncSocket LFData] withTimeout:-1 tag:0];


- (void)viewDidLoad 
    // initialize socket
    socket = [[AsyncSocket alloc] initWithDelegate:self];


#pragma mark AsyncSocket Delegate Methods
-(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag 
    NSLog(@"socket:%p didWriteDataWithTag:%@", sock, tag);


- (void)socket:(AsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag 
    NSLog(@"socket:%p didWritePartialDataOfLength:%@ tag:%@", sock, partialLength, tag);


- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port

    NSLog(@"socket:%p didConnectToHost:%@ port:%hu", sock, host, port);


- (void)socketDidSecure:(AsyncSocket *)sock

    NSLog(@"socket:%p socketDidSecure", sock);


- (void)socketDidDisconnect:(AsyncSocket *)sock withError:(NSError *)err

    NSLog(@"socket:%p socketDidDisconnect withError: %@", sock, err);


- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag

    NSString* newStr = [NSString stringWithUTF8String:[data bytes]];    
    NSLog(@"socket socketDidReadData:%@", newStr);


-(IBAction)disconnect:(id)sender  

#pragma mark View stuff
- (void)didReceiveMemoryWarning 
    [super didReceiveMemoryWarning];


- (void)viewDidUnload 

- (void)dealloc 
    self.socket = nil;
    [super dealloc];


@end

【讨论】:

【参考方案3】:

尝试使用本地 sock 读取命令,并将它们放入写入命令中

- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag

    [sock readDataToData:[AsyncSocket LFData] withTimeout:-1 tag:tag];

【讨论】:

嗯我尝试了[asyncSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];(和LFData)并从python服务器发送client_socket.send("xxx\r\n")并且委托没有触发。写委托也不会触发,但数据会被发送....嗯 如果写委托没有触发,请确保您设置正确 套接字asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];的初始化是否正确设置了代表? didConnectToHost 委托触发了,所以不是意味着其他 asyncsocket 委托也应该设置吗?我对可可编程很陌生,所以这对我来说有点新。我查看了a SOF question on delegates,但没有澄清。 AsyncSocket 对我来说真的很难设置 我试过了——没用。现在我正专注于让写委托被解雇;我知道数据被发送是因为服务器看到了它!我今天尝试了两种不同的方法。首先,我将服务器接收到的数据长度从 512 更改为每个套接字通信的 4 个,并从客户端发出一条 5 字节的消息。我想也许服务器在确认数据已发送之前正在等待完整的通信。没有工作 - 发送和接收消息,但没有代表解雇。然后,我使用消息代理类修改了 CocoaForScientists 示例,但这也不起作用!

以上是关于CocoaAsyncSocket 的读写委托不是触发和代码组织的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 上委托 Objective-C 协议

iOS即时通讯之CocoaAsyncSocket源码解析四

C#里事件和委托有啥区别啊??

CDN:无法下载中继 URL:https://cdn.jsdelivr.net/cocoa/Specs/1/d/4/CocoaAsyncSocket/7.6.1/CocoaAsyncSocket.po

(23)c#传智:单例模式,XML读写,委托,匿名函数,Lamda,多播委托

前端面试之js篇