Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking us to recommend or find a tool, library or favorite off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it.
Closed 9 years ago.
Improve this question
I want to implement a Voip app for iPhone.
How could i make peer to peer connection between users using socket programming with streaming.
Any source code available.
try GCDAsyncSocket
https://github.com/robbiehanson/CocoaAsyncSocket
or you can try this also
http://www.raywenderlich.com/3932/how-to-create-a-socket-based-iphone-app-and-server
define class properties:
NSInputStream *inputStream;
NSOutputStream *outputStream;
initialize your streams
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)kScannerIP, kScannerPort, &readStream, &writeStream);
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (__bridge NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
implement delegate method to handle incoming data:
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
switch (streamEvent) {
case NSStreamEventOpenCompleted:
break;
case NSStreamEventHasBytesAvailable:
break;
case NSStreamEventHasSpaceAvailable:
break;
case NSStreamEventErrorOccurred:
break;
case NSStreamEventEndEncountered:
break;
default:
NSLog(#"Unknown event");
}
}
finally close your network:
[inputStream close];
[outputStream close];
[inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
inputStream = nil;
outputStream = nil;
You can't; what would happen when both of your device's IP change (both moved to a different network)?
Related
I have used following code to connect to the server
- (void) initNetworkCommunication
{
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL,(CFStringRef)URLBASE, 8080, &readStream, &writeStream);
inputStream = (__bridge_transfer NSInputStream *)readStream;
outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
// open input and output stream of socket to send and receive data
[inputStream open];
[outputStream open];
}
and following code to send message using output stream
-(IBAction)sendMessage{
if (outputStream.hasSpaceAvailable) {
[outputStream write:[data bytes] maxLength:[data length]];
}
}
but when I try to send message the connection drops and gives connection reset by remote peer.
when I try to send message the connection drops and gives connection
reset by remote peer.
The error text unequivocally states that the peer dropped the connection, so you have to look there for the reason rather than in the code above.
I'm trying to create Bonjour client and in the process trying to setup input and output streams, I've successfully created the bonjour client, detected them and resolved them. After resolving I'm trying to setup input and output streams but when I tried sending message they do not go. The stream delegates are not getting called either, when I check the stream status it is always 1 (i.e opening), but never changes to open.
Here is what I'm doing to get streams:
-(void)viewDidAppear:(BOOL)animated
{
[self.service getInputStream:&inputStream outputStream:&outputStream];
if(inputStream && outputStream)
{
[outputStream setDelegate:self];
[inputStream setDelegate:self];
[self scheduleInCurrentThread];
[inputStream open];
[outputStream open];
NSLog(#"%lu",(unsigned long)inputStream.streamStatus);
NSLog(#"got Streams");
}
else
{
NSLog(#"failed to acquire streams");
}
}
#pragma mark - schedule in current thread
- (void)scheduleInCurrentThread
{
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
}
P.S: No object is nill.
I have an application that connects users to a serve. Users can connect to a host to communicate inserting an IP address and communicate using NSStream. Pressing the connect button starts a connection to the host and the user can receive and send messages.
I want to give a user the ability to disconnect from the server to not listen to pressing a disconnect button. The problem is that I am never able to successfully close the stream.
This is my current implementation:
// Create connection "Connect Button"
- (void)initNetworkCommunication:(UIViewController *)sender {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)#"123.456.789.123", 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];
controller = sender;
}
// Stop connection "Disconnect Button"
- (void)stopNetworkConnection {
[inputStream close];
[outputStream close];
[inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream release];
[outputStream release];
inputStream = nil;
outputStream = nil;
NSLog(#"Disconnect from stream");
}
The flow of operations is as follows:
User insert a valid IP address;
User press "Connect Button";
Everything works fine, connection established and user can send/receive messages;
User press "Disconnect Button" and user do not receive messages;
User press "Connect Button" but no longer able to connect
I tried this solution but it did not work:
NSStream closing and opening error
Thanks in advance for the help
I have written this code to setup a stream with a server:
-(void)streamOpenWithIp:(NSString *)ip withPortNumber:(int)portNumber;
{
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef)ip, portNumber, &readStream, &writeStream);
if(readStream && writeStream)
{
CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
//Setup inpustream
inputStream = (__bridge NSInputStream *)readStream;
[inputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
//Setup outputstream
outputStream = (__bridge NSOutputStream *)writeStream;
[outputStream setDelegate:self];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream open];
}
}
I am able to connect to the server and send & receive data. But I want to check if the connection is still there. If I disconnect a cable from the wifi router, I still can send data in the stream and no error occurred.
You can solve this on application level by using a timer to send some message and check if you receive something back. But you can solve this also with TCP Keep-Alive technique on a lower level.
How do I implement this with NSStream? How can I set the checking interval?
I assume that you get a NSStreamEventErrorOcurred when the stream is down by checking it with TCP Keep-Alive?
I have checked this post, but I can't figure it out:
Keeping a socket connection alive in iOS
Thanks for your help!
You can get the native socket handle with
CFDataRef socketData = CFReadStreamCopyProperty((__bridge CFReadStreamRef)(inputStream), kCFStreamPropertySocketNativeHandle);
CFSocketNativeHandle socket;
CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&socket);
CFRelease(socketData);
and then set socket options (you need to #include <sys/socket.h> for this):
int on = 1;
if (setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1) {
NSLog(#"setsockopt failed: %s", strerror(errno));
}
You could put this code in the event handler function for the kCFStreamEventOpenCompleted event:
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)event {
switch (event) {
case kCFStreamEventOpenCompleted:
if (stream == self.inputStream) {
CFDataRef socketData = CFReadStreamCopyProperty((__bridge CFReadStreamRef)(stream), kCFStreamPropertySocketNativeHandle);
CFSocketNativeHandle socket;
CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&socket);
CFRelease(socketData);
int on = 1;
if (setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1) {
NSLog(#"setsockopt failed: %s", strerror(errno));
}
}
break;
/* ... other cases ... */;
}
}
There is a more complete answer to a similar question.
For the example of the app that starts sending keepalive after 10 seconds, sends keppalive every 2 seconds and closes the stream after 4 keepalives with no reply, take a look at this post:
Is it possible to activate TCP keepalive on Apple iOS devices
It also shows how to set retransmission timeout after which the connection is closed.
I have a VoIP app that uses a TCP service to wake it up on incoming calls.
The TCP socket is created with this code fragment:
CFReadStreamRef read = NULL;
CFWriteStreamRef write = NULL;
...
CFStreamCreatePairWithSocketToHost(NULL,(__bridge CFStringRef)shost, port, &read, &write);
self.read = (__bridge NSInputStream*)read;
self.write = (__bridge NSOutputStream*)write;
if (![self.read setProperty:NSStreamNetworkServiceTypeVoIP
forKey:NSStreamNetworkServiceType]){
[Log log:#"Could not set VoIP mode to read stream"];
}
if (![self.write setProperty:NSStreamNetworkServiceTypeVoIP
forKey:NSStreamNetworkServiceType]){
[Log log:#"Could not set VoIP mode to write stream"];
}
self.read.delegate = self;
self.write.delegate = self;
CFRelease(read);
CFRelease(write);
[self.read scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[self.write scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[self.read open];
[self.write open];
I've also set the following:
VoIP & Audio in the info plist
Keep alive timer using [UIApplication sharedApplication] setKeepAliveTimeout
UIRequiresPersistentWiFi = YES in the info plist (quite sure it's not required, but...)
This works well while the app is in the foreground, and even works well in the background for a few minutes, but after a few minutes - the app does not receive any new TCP messages.
It doesn't work on wifi or 3G, same result for both.
I also tried setting the property just to the read stream (though the read and write point to the same socket).
Whenever I receive data on the TCP or send data I also start a short background task.
BTW - everything takes place on the main thread.
I've checked if the app crashes - it doesn't.
The same behavior can be observed while debugging on the device - after a while - nothing is received (no crashes, warnings, anything).
What am I doing wrong?
Looks like your code should work. But there may be two technical problems I can think of:
If you try this from LAN connection, while app in background the LAN router can close passive TCP connection because, in this case, SIP stack(guess you use SIP protocol) can't send data keep alive every 15 to 30 secs like it would in foreground.
Less likely, suppose you know what you doing, but since registration keep alive can be triggered only once in 10 minutes while in background, make sure that SIP server allows such a long expire period and you define it right in registration message.
Try the following code.Make sure you have only one voip socket in your app.
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)#"1.2.3.4",9999, &readStream, &writeStream);
CFReadStreamSetProperty(readStream,kCFStreamNetworkServiceType,kCFStreamNetworkServiceTypeVoIP);
CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
inputStream = (NSInputStream *)readStream;
[inputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
outputStream = (NSOutputStream *)writeStream;
[outputStream setDelegate:self];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream open];
In ViewController.h file add
#property (nonatomic, strong) NSInputStream *inputStream;
#property (nonatomic, strong) NSOutputStream *outputStream;
#property (nonatomic) BOOL sentPing;
In ViewController.m file add after #implementation ViewController
const uint8_t pingString[] = "ping\n";
const uint8_t pongString[] = "pong\n";
Add following code in viewDidLoad
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)(#"192.168.0.104"), 10000, &readStream, &writeStream);
//in above line user your MAC IP instead of 192.168.0.104
self.sentPing = NO;
//self.communicationLog = [[NSMutableString alloc] init];
self.inputStream = (__bridge_transfer NSInputStream *)readStream;
self.outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[self.inputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType];
[self.inputStream setDelegate:self];
[self.outputStream setDelegate:self];
[self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.inputStream open];
[self.outputStream open];
//After every 10 mins this block will be execute to ping server, so connection will be live for more 10 mins
[[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^{
if (self.outputStream)
{
[self.outputStream write:pingString maxLength:strlen((char*)pingString)];
//[self addEvent:#"Ping sent"];
}
}];
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
switch (eventCode) {
case NSStreamEventNone:
// do nothing.
break;
case NSStreamEventEndEncountered:
//[self addEvent:#"Connection Closed"];
break;
case NSStreamEventErrorOccurred:
//[self addEvent:[NSString stringWithFormat:#"Had error: %#", aStream.streamError]];
break;
case NSStreamEventHasBytesAvailable:
if (aStream == self.inputStream)
{
uint8_t buffer[1024];
NSInteger bytesRead = [self.inputStream read:buffer maxLength:1024];
NSString *stringRead = [[NSString alloc] initWithBytes:buffer length:bytesRead encoding:NSUTF8StringEncoding];
stringRead = [stringRead stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
//[self addEvent:[NSString stringWithFormat:#"Received: %#", stringRead]];
//if server response is 'call' then a notification will go to notification center and it will be fired
//immediately and it will popup if app is in background.
if ([stringRead isEqualToString:#"call"])
{
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = #"New VOIP call";
notification.alertAction = #"Answer";
//[self addEvent:#"Notification sent"];
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}
//else if ([stringRead isEqualToString:#"ping"])
//{
//if server response is 'ping' then a sting 'pong' will go to server immediately
//[self.outputStream write:pongString maxLength:strlen((char*)pongString)];
//}
}
break;
case NSStreamEventHasSpaceAvailable:
if (aStream == self.outputStream && !self.sentPing)
{
self.sentPing = YES;
if (aStream == self.outputStream)
{
[self.outputStream write:pingString maxLength:strlen((char*)pingString)];
//[self addEvent:#"Ping sent"];
}
}
break;
case NSStreamEventOpenCompleted:
if (aStream == self.inputStream)
{
//[self addEvent:#"Connection Opened"];
}
break;
default:
break;
}
}
Build your app and run
Open terminal in your MAC PC and write nc -l 10000 and press enter
$ nc -l 10000
Then write call and press enter