in ASIHTTPRequest class
I debug - (void)main method of the NSOperation with wireshark . I want to find which method send data.
But i debug to the end of startRequest in main method of NSOperation. I can't grab any data.
Because the read stream opens a socket connection with the server specified by the myUrl parameter when the CFHTTP request was created, some amount of time must be allowed to pass before the stream is considered to be open. Opening the read stream also causes the request to be serialized and sent.
base the above document of apple about "Communicating with HTTP Servers"
the most chance to send data is the below code .But it don't. I can't find something in wireShark.
CFStreamClientContext ctxt = {0, self, NULL, NULL, NULL};
if (CFReadStreamSetClient((CFReadStreamRef)[self readStream], kNetworkEvents, ReadStreamClientCallBack, &ctxt)) {
if (CFReadStreamOpen((CFReadStreamRef)[self readStream])) {
streamSuccessfullyOpened = YES;
}
}
where send data ???? like socket send or sendto function.
[request startAsynchronous];
and
[request startSynchronous];
If your program is for command line, just use [request startSynchronous] in main, because if you use asynchronous request, the main thread continue, when main thread terminate, maybe asynchronous request do nothing.
Related
OK i have tried a lot of different methods for this. I want to call a JSON API,get its response, save the key values, then call it again with different parameters. Most recently, I tried calling the URL method in a for loop, posting an NSNotification in connectionDidFinishLoading: and NSLogging values in observer when the notification gets posted. But its only logging the values of the final call multiple times.
I use this for the connection initialisation...
eventConnection=[[NSURLConnection alloc]initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]] delegate:self startImmediately:NO];
[eventConnection scheduleInRunLoop: [NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[eventConnection start];
This is the delegate method...
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSNotification *eventNotification=[NSNotification notificationWithName:#"eventsFound" object:nil userInfo:responseDict];
[[NSNotificationQueue defaultQueue]enqueueNotification:eventNotification postingStyle:NSPostNow coalesceMask:NSNotificationCoalescingOnName forModes:nil];
}
Any suggestions as to how i can achieve this?
To effectively chain multiple NSURLConnection requests, you should not start them all at once (e.g., like you say "in a for loop").
Instead, start the first request; then, from the connectionDidFinishLoading start the second; then again, when connectionDidFinishLoading is executed again, start the third and so on.
This is just a sketch of how you could do it to help you find a good design for your app; one possibility is:
define a state machine that is responsible for firing the requests depending on the current state; (the state could be a simple integer representing the sequential step you have go to);
start the state machine: it will fire the first request;
when the request is done, connectionDidFinishLoading will signal the state machine, so that it moves to the next step;
at each step, the state machine fires the request corresponding to that step.
There are other design options possible, of course; which is the best will depend on your overall requirements and the kind of call flow you need.
set a counter and total number of requests to send. and in connection did finished loading, check that if counter is reached to total number of rquests to send else call the method again in which you was sending the data, and increment sent requests. if u use data from file. i.e. first write data to file wid a number and then read it when u want to send request, then it wud b great
Hum,
Did you try to use Libraries like AFNetworking, you can create asynch request and using blocks to handle answers.
You can use NSOPerationQueue or Block or thread for same. Call another function after finishing one.
I'm using an NSMutableURLRequest to perform a simple file upload from iOS5 to a custom server. When I send the request, I have it print out the length of bodyContents, which contains the body of the request. For the particular request I am working on, it will say that the length is 46784. I don't set the content-length, since I found out it was doing that automatically, but I pull the info anyway in case I need it later. The headers being received by the server say that the content-length is 46784. When I do a character count on the body at the server end, it tells me that the length of the body is 46788, 4 too many. I ran another request, again, the request had 4 more characters than what I sent.
At first, I thought it had to be on the server side, just because it didn't make any sense. So I sent a request from a test program that I know works to the server, and checked the length of the body it sent against the content-length header and they were identical.
What is the best way to deal with this? Should I manually set the content-length to 4+[bodyContents length]? I don't think that would be what I would want to do, just because I shouldn't have to add extra space for data I don't know that I want.
Here is the code that sends the request
-(void)send:(id)delegate
{
bodyContents = [bodyContents stringByAppendingFormat:#"--%#--",boundry];
NSInteger length = [bodyContents length];
NSLog(#"Length is %i",length);
[request setHTTPBody:[bodyContents dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:delegate];
if(connection)
{
NSLog(#"Connection good");
}
else
{
NSLog(#"Connection bad");
}
}
I set the content-type property of the request in the init method of the class.
Any ideas?
When you specify an encoding, the size of the contents can change... get the size after you set the HTTPBody and then see if that adjusts things up by four bytes automatically.
I am using ASIHTTPRequest to download some data.
I have the following in a method:
// Request 1
request1.tag = 1;
[request1 setDelegate:self];
[request startAsynchronous];
// Request 2
request2.tag = 2;
[request2 setDelegate:self];
[request2 startAsynchronous];
// Call third request method
[self callThirdRequest];
Now from within callThirdRequest, I am grabbing some data that has been downloaded from request2 and in there, I am calling startAsynchronous. The reason I have the calling of the third request in a separate method is because it will get invoked more than once. After putting some console outputs, it seems that callThirdRequest is being invoked before request2 starts its download. Therefore, when callThirdRequest tries to grab some data which should have been downloaded by request2, it does not work as there is no data.
Why is that? How can I make sure callThirdRequest is only called when request2 is done downloading?
Thanks,
When a request is run asynchronously, the rest of your code will continue to run at the same time. Your first two requests are doing exactly that. You have two options.
You can run the second request synchronously. (Not a good idea, since your app will appear "frozen" until the second request completes. Also, using this method won't help you if the second request, in your list of three, fails.)
A much better idea would be to use delegate callback methods. This is the better way of dealing with this, for two reasons. First of all, you can handle failed requests properly, and also, you can handle successful requests properly. Yu want something like this:
// Request 2
request2.tag = 2;
[request2 setDelegate:self];
[request2 startAsynchronous];
- (void)requestFinished:(ASIHTTPRequest *)request{
if(request.tag == 2){
[self callThirdRequest];
}
}
Make sure to check the request in the delegate callback, to ensure that it's the "second" one, so that you don't end up firing the wrong action at the wrong time. In this case, I used the "tag" property of the request. If you would have retained the request as a property of your class, you can just check for that as well.
That is because request2 is running asynchronous. You should start the 3rd request in the request-did-finish-delegate-method of request2!
The reason is startAsynchronous. An asynchronous call will operate on another thread. You need to set the delegate on request2 and then call the third request when request2 is finished.
// Request 2
request2.tag = 2;
[request2 setDelegate:self];
[request2 startAsynchronous];
...
- (void)requestFinished:(ASIHTTPRequest *)request
{
[self callThirdRequest];
}
Before I dive into ASIHttpRequest's source code:
From the documentation (http://allseeing-i.com/ASIHTTPRequest/How-to-use) of ASIHttpRequest it is not completely clear to me when an ASIHttpRequest will call requestDidFinishSelector or requestDidFailSelector.
When does a request fail?
Is it correct to assume that whenever the server responds (with a corresponding HTTP status code, be it a 1xx, 2xx, 3xx, 4xx or 5xx, the request is considered successful, and therefore requestDidFinishSelector will apply?
Is 'failure' the fact that the server could not be reached?
As I type this, this seems to be the most logical answer... anyway.
Yes, ASIHTTPRequest doesn't use HTTP status codes (except for redirection), so it's up to you to look out for problems (ex: 404) in your requestDidFinishSelector selector.
int statusCode = [request responseStatusCode];
NSString *statusMessage = [request responseStatusMessage];
requestDidFailSelector will be called only if there is the server can not be reached (time out, no connection, connection interrupted, ...)
You're right — a request succeeds if the server responds with a HTTP status code. You can ask for this status code by using ASIHTTPRequest's responseStatusCode.
If the request URL is invalid or your app has no access to the Internet, then your request fails. So you should implement requestDidFailSelector (or specify your own error handling method) and handle errors in there in any case.
I am currently doing many server side computations that take a while to process.
In the mean time I redirect the user to the same page until it has a response.
This is resulting in a "too many HTTP redirects" error. Is there a way to disable this, or increase its threshold?
This happens on the simulator and on the phone.
here is the relevant code:
//Define request
NSURLRequest *request = [requestGenerator theRequest];
// Execute URL and read response
NSError *error = nil;
NSHTTPURLResponse *httpResponse;
NSData *resp = [NSURLConnection sendSynchronousRequest:request returningResponse:&httpResponse error:&error];
//If we get a good response
if(resp != nil && httpResponse != NULL && [httpResponse statusCode] >= 200 && [httpResponse statusCode] < 300)
{
...
}
if (error) {
[self showErrorMessage:error];
}
Redirecting to the same URL is extremely wasteful. At the very least, assign the "job" an ID and return that to the calling app. It can then poll the server, passing up the ID, to see when the job completes. You should not poll too frequently, perhaps once every few seconds.
You can also just use a single request-response. Your server will simply not respond until it has the data. On the iPhone the default time-out is set to 60 seconds. Your server may be able to start a response (write out a little data) so the connection is established; but do not complete & close the connection until processing completes.
Finally, if you do a simply request ... long delay ... response; and expect it will take > 60 seconds - consider extending the timeout of the request via NSMutableURLRequest's setTimeoutInterval.
Note: in your example you are using a synchronous request. If you do that outside of a thread, your app can block. If it blocks for > 20 seconds, it will be killed by the watchdog service. It's very easy to use the asynch methods with delegates to catch the responses, so give them a whirl.
Finally, if you use the asynch methods; you can catch the 3xx redirect and handle it yourself; but you know, your redirect technique seems evil so don't do it.