I'm trying to create a simple iPhone app that can communicate with a server (which is running on my computer at the moment and works fine). I've been trying to use the NSStream class but have had a lot of issues. I really just want to mimic a telnet-type of connection using the streams. I've managed to send data to my server with an NSOutputStream, but I can't figure out how to use the NSInputStream to read the reply sent from the server. Here is the method I have so far:
-(void)sendName:(NSString *)name{
NSData*nameData = [name dataUsingEncoding:NSUTF8StringEncoding];
[outputStream write:(uint8_t *)[nameData bytes] maxLength:[nameData length]];
//The server sends a reply here.
[inputStream read:? maxLength:?]; // I don't know what do to here.
[inputStream close]; //Created and opened elsewhere.
[outputStream close]; //Created and opened elsewhere.
}
I can't figure out how to get the inputStream to read what the server sends. I've tried passing an NSData object in as the buffer but it always crashes. So how do I create the buffer? Also, is it bad to make the length huge to make sure the buffer doesn't fill up (though maybe waste space)? Some example code would be splendid! Thanks in advance!
The thing you need to understand about NSStreams, is "don't call us, we'll call you." When the stream has data available, it will notify its delegate, and then you read whatever data is available and tell it to go get some more.
Read the Streams Programming Guide
Related
Will [NSData dataWithContentsOfURL:url] either return the full amount of bytes on success, or nil if something goes wrong?
Is there a chance, that it would return maybe only half of the bytes of the content... perhaps if their internet connection fails halfway through?
If there is a chance that it would return only partial data, is there some other function I could use that would be more reliable and I would be able to know definitely whether they got the full amount of data or not?
I'm not sure about the implementation of -dataWithContentsOfURL: but using a sychronous method like this is not really recommended anyway.
Something based on NSURLConnection is your best bet, but you need to be aware of a few things. Most people don't realize that if the server disconnects while an NSURLConnection is receiving data, it will not cause the download to fail with an error. The -connectionDidFinishLoading: delegate method will be called as normal. Many people get this wrong.
If you want to be sure you have all the data, you need to handle the -connection:didReceiveResponse: delegate method and save the value of [response expectedContentLength]. Then in -connectionDidFinishLoading: you can make sure you received the same number of bytes as expected, and generate an error if not.
There are many free libraries out there based on NSURLConnection like AFNetworking. However you need to beware of bad code. I've just checked the source to AFNetworking and it appears they also do not check for the case where the server sends back less data than the Content-Length header specifies. Also note that the popular ASIHTTPRequest is no longer being actively developed and has received some criticism over its implementation.
I'll leave it up to others to suggest other alternative libraries, but NSURLConnection is the right direction.
If you 'worry' about such a thing I'd recommend using NSURLConnection with it's appropriate delegates.
The async approach (that is NSURLConnection) is imho always better.
I have a simple HTTP server running that pretty much just serves an MP3 file in chunks of equal size. I'm writing an iOS app (for testing purposes), that basically takes a URL and streams the file through MPMovieController. Here's my sample code:
MPMoviePlayerController *mp = [[MPMoviePlayerController alloc] init];
[mp setMovieSourceType:MPMovieSourceTypeStreaming];
mp.contentURL = [NSURL URLWithString:#"http://127.0.0.1:8080"];
[mp play];
It works. BUT: on my http server I see multiple connections (first one breaks right away, second one streams to the end usually, although sometimes there is 3rd connection).
I know it's not the server issue, since when I do this:
NSData *myData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://127.0.0.1:8080"]];
...then there's only 1 connection that finishes reading and disconnects.
The question is: Why does MPMoviePlayerController need to establish and break those connections before finishing reading the file, why doesn't it just keep waiting for more data to be written on the socket? I haven't been able to find any relevant docs that would explain this :(
P.S. If you are curious why I need this, here's a short explanation: I'm trying to emulate real life network scenarios where bytes are received by the MPMovieController in chunks with small delays of random length in between
You need to modify your server and add support for HTTP 206 Partial Content requests/responses. iOS requests movie data over HTTP this way.
So I have a pretty simple problem, which I have no idea how to go about (kinda of new for everything here). I am developing an iPhone app that I intend to use only myself - so think small for now :)Let's say all my app is doing is tracking my location every hour. All I want to do, is to be able to read this information not on the iphone, say on a file on my computer. How can I send this information from my app to a personal computer? I am guessing that I will need to set up some server / database or something on my personal machine?
Can someone please help with a quick step by step on how to go about that? I literally have no clue where to start...
Thanks!
You just need a http server and then you cam create HTTP GET/POST requests to url's set up on your machine. You can use the responses to send data back to the device.
You'll need to have a listener somewhere to send your data to. For instance, you could set up a communication class in your project which would be responsible for serving as the medium between your applications. You would then set up a listener on a server, or your machine that would listen for requests.
iPhone > Communication Class > Web service
(.NET in this case)
You can use the NSURLConnection object to serve this purpose. E.g.
- (void) sendSomethingToServer:(NSString*)myData{
NSString*url = [[NSString alloc]initWithFormat: #"http://example.com/service.asmx/RecordData?myData='%#'", myData];
[self createRequest:url];
[url release];
}
http://example.com/service.asmx/RecordData being the location and method on your web service.
Here's a generic request method I created which sets the headers as a JSON packet.
- (void) createRequest: (NSString*)urlFormatted {
NSLog(#"Request Sent");
NSURL *url = [NSURL URLWithString: urlFormatted];
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL: url];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/json; charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
}
And on the back-end, on your web server, you would have a method that recieves the data. Obviously you could use any technology you wanted on the server. In this example, I'm using .NET on Mono e.g.
[WebMethod(Description = "Generic Client Data)]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public string RecordData(string myData)
{
// Do something with data
}
Set up a Ruby on Rails server on your Mac. It's free and quite easy.
Use ASIHTTPRequest to send data to the Ruby server.
http://allseeing-i.com/ASIHTTPRequest/
If you just need to get the data back and forth, I believe you could use file sharing. Here's a tutorial on how to set that up:
http://www.raywenderlich.com/1948/how-integrate-itunes-file-sharing-with-your-ios-app
It would allow you to view the files in itunes and copy them back and forth when the iPhone is connected via USB. If all you need to do is to get a raw data file onto your computer, that would likely be a lot less overhead than having to build/run a full server just to transfer the file over.
Apple's can you help get started. Search for "networking" in the docs and develop a client on both sides which uses your own protocol.
I'd like to be able to get my iphone to load a URL( or really the file that the url points to) into a string. The reason I want to be able to do this is so that I can then parse the string looking for tags and extract some values from it.
The files are mostly webpages so html or .asp etc.
Anybody able to give me some hints on what I need to do to achieve this kinda of thing?
Many Thanks,
-Code
First get the URL
NSURL *anUrl = [NSURL URLWithString:#"http://google.com"];
Then turn it into a string
NSError *error;
NSString *htmlString = [NSString stringWithContentsOfURL:anUrl encoding:NSUTF8Encoding error:&error];
UPDATE:
There is documentation on getting the contents of an URL by using NSURLConnection from the ADC site
From there you can get the string representation of the downloaded data using
NSString *htmlString = [[NSString alloc] initWithData:urlData encoding:NSUTF8Encoding];
I appreciate that this has been asked and answered, but I would strongly suggest that you consider not using NSString's stringWithContentsOfURL:encoding:error: method for this. If there's one message Apple has tried to send to iOS developers over the past year it is this: Do not make synchronous network calls on the main thread.
If that request takes more than twenty seconds to respond, which is not at all unlikely with a 3G or EDGE connection, and certainly possible on a WiFi connection, iOS will kill your app. More importantly, if it takes more than about half a second to return you're going to anger your users as they fiddle with their unresponsive phones.
NSURLConnection is not terribly difficult to use, and will allow your device to continue responding to events while it's downloading content.
when iPhone connects to a wireless router, and that router is not connected to the internet? i need to display an error message saying "check you internet connection" i tried the Reachability sample code. but no luck,
http://developer.apple.com/library/ios/#samplecode/Reachability/Listings/ReadMe_txt.html
when i disable the WIFI in phone it's working fine, i tried the Checking For Internet Connectivity in Objective C sample code "isDataSourceAvailable" even itz not working,can any one help me to fix this issue, really appriciate.
You could do something like this:
+ (BOOL) pingServer
{
NSURL *url = [NSURL URLWithString:#"http://some-url-that-has-to-work/"];
NSURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSHTTPURLResponse *response = nil;
[NSURLConnection sendSynchronousRequest:request
returningResponse:&response error:NULL];
return (response != nil);
}
This is a synchronous request, so that it will block the current thread. You can do the whole network check in a background thread, so that blocking it won’t matter, or you can send the request asynchronously. Also you might want to set the HTTP method to HEAD, so that you won’t download the whole resource.
I recommend you do the same as Microsoft does, and to be really wicked, you can even use their servers, since they probably will make sure those are on line for the foreseeable future.
They look up a hostname and then access a very small file on a web server.
See the same question on serverfault (from a non programming perspective of course.)
Basically look up the IP address for a hostname (in that example "dns.msftncsi.com"), then access the URL, for example http://msftncsi.com/ncsi.txt. This can be done with simple socket programming if you like, real HTTP not necessary.
Open a socket to port 80, on the IP you found by looking up the hostname.
Send a string to the socket like so:
"GET /msftncsi.com/ncsi.txt HTTP/1.1\nHost: msftncsi.com:80\n\n"
Then wait for something to return. If anything returns, even a single byte, it means you have Internet access.
Or at least access to this server, which in this example is Microsoft.
https://github.com/adib/asi-http-request/blob/master/External/Reachability/Reachability.h
This is a part of the ASI HTTPRequest project on git. It extends Apple's example and apparently is good enough for quite a few apps in the store (see ASI's wall of who's using: http://allseeing-i.com/ASIHTTPRequest/Who-is-using-it)
Anywho, I know an answer was already accepted, but just for further reference.