Here is the issue. When my app starts up, I connect to server1 at port 5000. I send to data to server1. Server1 sends data back. Server1 close connection. NSStreamEventEndEncountered event occurs for inputStream. Then I connect to server2 at port 5001. I try to send data to server2, but the data ends up going to server1. Somehow the inputStream is connected at port 5001 and my outputStream isconnected at 5000. What am I doing wrong?
- (void) initNetworkCommunication: (uint32_t)port {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)#"localhost", port, &readStream, &writeStream);
inputStream = (NSInputStream *)readStream;
outputStream = (NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
}
- (void) onClientConnectionLost {
if (atServer1 == YES) {
atServer1 = NO;
[self initNetworkCommunication: 5001];
}
if (atServer1 == NO) {
atServer1 = YES;
[self initNetworkCommunication: 5000];
}
}
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
if (theStream == inputStream) {
//handle packets...
}
break;
case NSStreamEventErrorOccurred:
NSLog(#"Can not connect to the host!");
break;
case NSStreamEventEndEncountered:
if (theStream == inputStream) {
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[theStream release];
theStream = nil;
[outputStream close];
[outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream release];
outputStream = nil;
[self onClientConnectionLost];
}
break;
default:
NSLog(#"Unknown event");
}
}
- (void) onClientConnectionLost {
if (atServer1 == YES) {
atServer1 = NO;
[self initNetworkCommunication: 5001];
}
else if (atServer1 == NO) {
atServer1 = YES;
[self initNetworkCommunication: 5000];
}
}
On your old code... when atServer1 = YES, it will execute the first if statement.... which sets atServer1 to NO... so second if statement is TRUE.. so it will also executes that..
Related
I'm currently creating a chat app based off of Rey Wenderlich's chat app tutorial which is going great except I can't seem to reconnect without having to run the app from Xcode again.
It goes something like this: run server -> run app (At this point, everything is great) then I stop server -> run server again at which point my streams refuse to reconnect and keep giving me the erorr: Error Domain=NSPOSIXErrorDomain Code=61 "Connection refused".
Any ideas why this is?
Method to init streams:
- (void)initStreams {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)SERVER_IP, port, &readStream, &writeStream);
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (__bridge NSOutputStream *)writeStream;
inputStream.delegate = self;
outputStream.delegate = self;
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
}
My delegate
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
NSString *streamName = #"Output Stream";
if (aStream == inputStream) {
streamName = #"Input Stream";
}
switch (eventCode) {
case NSStreamEventOpenCompleted:
NSLog(#"%# opened! (%lu)",streamName, eventCode);
[_delegate socketDidOpenSuccessfully];
break;
case NSStreamEventHasBytesAvailable:
[self readDataFromStream:aStream];
break;
case NSStreamEventErrorOccurred:
NSLog(#"Error: %#",[aStream streamError]);
[self resetStreams];
break;
case NSStreamEventEndEncountered:
NSLog(#"%# read ended! (%lu)",streamName, eventCode);
[self resetStreams];
break;
default:
NSLog(#"Unknown %#: %d",streamName, (int)eventCode);
break;
}
}
Reset streams Method:
- (void)resetStreams {
NSLog(#"Reseting!");
toSend = [NSMutableArray new];
_loginStatus = LTLoginStatusLoggedOut;
[inputStream close];
[outputStream close];
[self performSelector:#selector(initStreams) withObject:self afterDelay:2];
}
So after hours of frustration, I decided to just wrap it in another object and re instantiate that whenever it gets disconnected. Seems to work whereas re-initiating the stream does not.
I am working through a tutorial for a chat messaging app. I typed in the code in the ViewController.m but I am getting these error messages:
Parse Issue Expected identified or ‘(‘
(for the 1st bold line in the code below) and
Semantic Issue Method definition for ‘initNetworkCommunication’ not
found
(for the 2nd bold line in the code below)
How can I resolve these issues? Note: I am using Xcode 6.4
#import "ViewController.h"
#interface ViewController ()
**- (void)initNetworkCommunication; {**
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)# 192.168.99.2, 80, &read-Stream,&writeStream);
inputStream = (NSInputStream *)readStream;
outputStream = (NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoop-Mode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode: NSDefaultRunLoop-Mode];
[inputStream open];
[outputStream open];
[self initNetworkCommunication];
}
#end
**#implementation ViewController**
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)joinChat:(id)sender {
}
#end
Make this:
- (void)initNetworkCommunication; {
This:
- (void)initNetworkCommunication {
And move this:
- (void)initNetworkCommunication {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)# 192.168.99.2, 80, &read-Stream,&writeStream);
inputStream = (NSInputStream *)readStream;
outputStream = (NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoop-Mode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode: NSDefaultRunLoop-Mode];
[inputStream open];
[outputStream open];
[self initNetworkCommunication];
}
Below this:
#implementation ViewController
You want to take out the semi-colon in this line:
- (void)initNetworkCommunication; {
It's just not proper syntax having that there.
I'm writing a messaging app that uses a NSStream to communicate with a server written in Python. The server works perfectly with a companion Python client. But when I connect to it with a NSStream, the NSInputStream doesn't seem to get any data. The NSOutputStream, however, works perfectly. I am opening the string like so:
-(void)openStream
{
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)#"tihmstar.dyndns.org", 80, &readStream, &writeStream);
inputStream = (__bridge_transfer NSInputStream *)readStream;
outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
[self auth];
[[NSNotificationCenter defaultCenter] postNotificationName:#"InitCompleted" object:nil];
}
The delegate method is as so:
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
{
NSLog(#"Handle Event - ");
switch (streamEvent)
{
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
NSLog(#"Bytes Available!");
if(theStream == inputStream)
{
NSLog(#"inputStream is ready.");
uint8_t buf[1024];
unsigned int len = 0;
len = [inputStream read:buf maxLength:1024];
if(len > 0)
{
NSMutableData* data=[[NSMutableData alloc] initWithLength:0];
[data appendBytes: (const void *)buf length:len];
NSString* string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"Server said- %#", string);
[self messageReceived:[string lowercaseString]];
}
}
break;
case NSStreamEventErrorOccurred:
NSLog(#"Can not connect to the host!");
break;
case NSStreamEventEndEncountered:
NSLog(#"End Encountered");
break;
case NSStreamEventHasSpaceAvailable:
NSLog(#"Space Availible.");
break;
default:
NSLog(#"Unknown event- %u", streamEvent);
}
}
My problem is that case NSStreamEventHasBytesAvailable is never called, and therefore the message from the server is never being received. Anyone have any solutions for this? I've found some related questions here on StackOverflow, but none of them have been answered.
Thanks in advance.
I was just looking into the code. try to remove delegate of NSInputStream. I was looking into the another Using NSXMLParser initWithStream: no parser delegate methods received
which deals with similar situation.
I don't know exactly the answer for your question but I know exactly that you shouldn't call
[self auth];
after NSStream open right away. You have to wait for
NSStreamEventHasSpaceAvailable
event for your NSOutputStream and write data inside it afterwards only.
I'm trying to connect to a server in a custom GCD queue. This is how I'm doing it.
- (void) initNetworkCommunication{
if(!self.connQueue){
self.connQueue = dispatch_queue_create("connection_queue", NULL);
}
dispatch_async(self.connQueue, ^(void) {
if(self.inputStream ==nil && self.outputStream ==nil) {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
NSString *host= [[NSUserDefaults standardUserDefaults] objectForKey:#"ip_preference"];
NSNumber *portNum = [[NSUserDefaults standardUserDefaults] objectForKey:#"port_preference"];
int port = [portNum intValue];
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);
CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
self.inputStream = (__bridge NSInputStream *)readStream;
self.outputStream = (__bridge NSOutputStream *)writeStream;
[self.inputStream setDelegate:self];
[self.outputStream setDelegate:self];
[self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[self.outputStream open];
[self.inputStream open];
} else {
NSLog(#"persistant connection alerady opened");
return;
}
});
}
Now, if I write this piece of code in dispatch_sync, it calls delegate function correctly.
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
But, when I use dispatch_asynch, which is what I want to do, it does not call my delegate function.
From what I've read on SO so far, GCD queues have a runloop associated with them but these are not run by the system and we need to do so ourselves. I understand this in theory, but but how is it done. Dispatch sources associated with this somehow?
Thank You in advance.
Add this method after [self.inputStream open];
[[NSRunLoop currentRunLoop]run];
This puts the receiver into a permanent loop, during which time it processes data from all attached input sources.
See apple docs about RunLoops
The other way let run on dispatch_get_main_queue when use dispatch_async();
Does anyone know of a simple example that creates (network-based) NSStreams on a separate thread?
What I am actually trying to do is unschedule (from the main thread) and reschedule (to a helper/network thread) an open NSInputStream and NSOutputStream that I am receiving from a third party framework (see Can an open, but inactive, NSStream that is scheduled on the main thread be moved to a different thread?). Nobody has answered that question thus far, so I am trying to do this myself to see if it could be made to work.
To test what is possible, I am trying to modify the code here (which includes a iOS client and a very short, python-based server [awesome!]):
http://www.raywenderlich.com/3932/how-to-create-a-socket-based-iphone-app-and-server
so that after the NSInputStream and NSOutputStream is created and opened I attempt to move it onto a helper thread.
The challenge that I am experiencing is that the helper thread does not seem to be responding to delegate messages from the streams or any messages that I am sending via:
performSelector:onThread:withObject:waitUntilDone:modes:. I suspect that I am doing something wrong with setting up the helper thread's NSRunLoop (see networkThreadMain below).
So, [ChatClientViewController viewDidLoad] now looks like:
- (void)viewDidLoad {
[super viewDidLoad];
[self initNetworkCommunication];
[self decoupleStreamsFromMainThread];
[self spoolUpNetworkThread];
inputNameField.text = #"cesare";
messages = [[NSMutableArray alloc] init];
self.tView.delegate = self;
self.tView.dataSource = self;
}
With these implementations:
- (void) initNetworkCommunication {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)#"localhost", 80, &readStream, &writeStream);
inputStream = (NSInputStream *)readStream;
outputStream = (NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
}
- (void) decoupleStreamsFromMainThread
{
inputStream.delegate = nil;
outputStream.delegate = nil;
[inputStream removeFromRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode];
[outputStream removeFromRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode];
}
- (void) spoolUpNetworkThread
{
[NSThread detachNewThreadSelector: #selector(networkThreadMain) toTarget: self withObject: nil];
}
- (void) networkThreadMain
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Top-level pool
static dispatch_once_t once;
dispatch_once(&once, ^{
[self rescheduleThreads];
((ChatClientAppDelegate * )[[UIApplication sharedApplication] delegate]).networkThread = [NSThread currentThread];
[inputStream setDelegate:self];
[outputStream setDelegate:self];
NSLog(#"inputStream status is: %#", [NSInputStream streamStatusCodeDescription: [inputStream streamStatus]]);
NSLog(#"outputStream status is: %#", [NSOutputStream streamStatusCodeDescription: [outputStream streamStatus]]);
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate distantFuture]];
});
[pool release]; // Release the objects in the pool.
}
- (void) rescheduleThreads
{
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
Any ideas on what might be wrong? Thanks in advance!
Something along the lines of the code in the question below works well ( I have similar code in my app):
How to properly open and close a NSStream on another thread