In the startLoading method of my URLProtocol subclass, I create a URLSession and URLSessionStreamTask. I resume the task and add a BlockOperation to call my first transaction method. That method uses URLSessionStreamTask.write. If I don't get an error, another BlockOperation is placed with my second transaction method. That method uses URLSessionStreamTask.read and it always times out.
The error looked like:
Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x10945dff0 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=gopher://www.floodgap.com:80/GET%20/, NSErrorFailingURLKey=gopher://www.floodgap.com:80/GET%20/, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.}
Can a stream-task only be used for one I/O call? Or only just writing or just reading? Or is there some mode-switch function I forgot to call between the write and read? Could there be another problem?
Try to add read block operation before write to the streamTask. Read and write are asynchron calls, waiting until timeout happens.
In your example you send a command with write, I guess it receives and answer very quick, before adding read to the task is done. So you never see your response.
Related
Trying to see if I can get a response from ctrader server.
Getting no response and seems to hang at "s.recv(1024)". So not sure what could be going wrong here. I have limited experience with sockets and network coding.
I have checked my login credentials and all seems ok.
Note: I am aware of many FIX engines that are available for this purpose but wanted to
try this on my own.
ctrader FIX guides
require 'socket'
hostname = "h51.p.ctrader.com"
port = 5201
#constructing a fix message to see what ctrader server returns
#8=FIX.4.4|9=123|35=A|49=demo.ctrader.*******|56=cServer|57=QUOTE|50=QUOTE|34=1|52=20220127-16:49:31|98=0|108=30|553=********|554=*******|10=155|
fix_message = "8=FIX.4.4|9=#{bodylengthsum}|" + bodylength + "10=#{checksumcalc}|"
s = TCPSocket.new(hostname, port)
s.send(fix_message.force_encoding("ASCII"),0)
print fix_message
puts s.recv(1024)
s.close
Sockets are by default blocking on read. When you call recv that call will block if no data is available.
The fact that your recv call is not returning anything, would be an indication that the server did not send you any reply at all; the call is blocking waiting for incoming data.
If you would use read instead, then the call will block until all the requested data has been received.
So calling recv(1024) will block until 1 or more bytes are available.
Calling read(1024) will block until all 1024 bytes have been received.
Note that you cannot rely on a single recv call to return a full message, even if the sender sent you everything you need. Multiple recv calls may be required to construct the full message.
Also note that the FIX protocol gives the msg length at the start of each message. So after you get enough data to see the msg length, you could call read to ensure you get the rest.
If you do not want your recv or read calls to block when no data (or incomplete data) is available, then you need to use non-blocking IO instead for your reads. This is complex topic, which you need to research, but often used when you don't want to block and need to read arbitary length messages. You can look here for some tips.
Another option would be to use something like EventMachine instead, which makes it easier to deal with sockets in situations like this, without having to worry about blocking in your code.
How is it possible to repeatedly read from a NamedPipe in Windows? I get an 109 error, saying it could not open pipe, if I have a ReadFile() function after another ReadFile() function.
of course this is possible and need do after your pipe is connected and until disconnect. 109 this is ERROR_BROKEN_PIPE - you got this error in ReadFile when another end is close pipe handle, by call CloseHandle. in this case you need call DisconnectNamedPipe and then wait for new client by call ConnectNamedPipe. after connection is complete - you need just call ReadFile , in read completion again call ReadFile and so on until disconnect - some error returned. if you got error ERROR_PIPE_NOT_CONNECTED in ReadFile (just or in completion) this mean that remote end call DisconnectNamedPipe - your pipe already disconnected, so you can skip call to DisconnectNamedPipe and just call ConnectNamedPipe.
I want to send notifications to apple devices in batches (1.000 device tokens in batch for example). Ant it seems that I can't know for sure that message was delivered to APNs.
Here is the code sample:
ssl_connection(bundle_id) do |ssl, socket|
device_tokens.each do |device_token|
ssl.write(apn_message_for device_token)
# I can check if there is an error response from APNs
response_has_an_error = IO.select([socket],nil,nil,0) != nil
# ...
end
end
The main problem is if network is down after the ssl_connection is established
ssl.write(...)
will never raise an error. Is there any way to ckeck that connection still works?
The second problem is in delay between ssl.write and ready error answer from APNs. I can pass timeout parameter to IO.select after last messege was sent. Maybe It's OK to wait for a few seconds for 1.000 batch, but wat if I have to send 1.000 messages for differend bundle_ids?
At https://zeropush.com, we use a gem named grocer to handle our communication with Apple and we had a similar problem. The solution we found was to use the socket's read_non_block method before each write to check for incoming data on the socket which would indicate an error.
It makes the logic a bit funny because read_non_block throws IO::WaitReadable if there is no data to read. So we call read_non_block and catch IO::WaitReadable before continuing as normal. In our case, catching the exception is the happy case. You may be able to use a similar approach rather than using IO.select(...).
One issue to be aware of is that Apple may not respond immediately and any notifications sent between a failing notification and reading from the socket will be lost.
You can see the code we are using in production at https://github.com/SymmetricInfinity/grocer/blob/master/lib/grocer/connection.rb#L30.
I have come across this problem a few times and never been able to resolve it but now I need to solve it once and for all.
I have a procedure which has been throwing runtime errors. This is not a problem as I have an error handler defined at the top of the function and the handler at the bottom something like this:
retryConcat:
On Local Error GoTo concatErr
'Some Code here
Exit Sub
concatErr:
If MsgBox("Could not append the receipt for this transaction to the Receipt viewer logs.", vbExclamation + vbRetryCancel, "Warning - Missing Receipt") = vbRetry Then
err.Clear
GoTo retryConcat
End If
The error handler contains a message box allowing the user to retry if required. Now here is the part which confuses me. The first time an error is thrown it shows the message box and allows the user to retry as expected. The program then jumps to the appropriate line and tries again. However the second time through when the error is thrown it does not jump to the error handler, it jumps out of the procedure and the error handler in the parent catches it instead!
So my question is why does it jump to the parent error handler on subsequent throws. This happens in many places all over my code. In many cases where I can manually check for errors I can stick the code in a while loop to solve it but with runtime errors I am forced to use the error trapping which acts in this rather annoying way.
Any help or advice would be appreciated.
You need ot use Resume retryConcat.
When an error occurs, it jumps into the error handle to concatErr:. You then show the message box, and if the user chooses to retry, the code then jumps to retryConcat. As this you used Goto, it DOES NOT exit the error handler, and so next time the error occurs, it's already in the error handler and has no choice but to raise the error up the chain to the calling procedure.
Using Resume concatRetry allows it to exit the error handler and resume at the required point, meaning next time the error occurs, it can handle is again.
It probably makes it easier to understand, if you imagine the error handler is a state, not a section of code.
Friends,
I have a non-blocking TCP socket (on AIX). When I attempted connect() I got EINPROGRESS. My question is if I call recv() before connection completion, what would be the (most apprpriate) error code?
I saw that, in case connection fails, and I call recv(), I got ECONNREFUSED; means I got an error corresponding to my earlier connect() attempt. Taking same logic I should get EINPROGRESS for recv(). Am I right in my approach ?
If yes, this raises another question - Why such error codes are not included amongst error codes of recv()?
I have only seen EAGAIN returned in this case, just as you would see in the case where there's no data to read. For writing to a non-connected socket, you typically get ENOTCONN, though I believe some platforms might give you EAGAIN.
Here's a trivial Python script to demonstrate:
import socket
# Any address that does not succeed or fail right away will do
ADDR = "192.168.100.100"
PORT = 23
s = socket.socket()
s.setblocking(False)
try:
s.connect((ADDR, PORT))
except socket.error, e:
print "Connect gave us",e
try:
s.recv(1)
except socket.error, e:
print "Read gave us",e
try:
s.send("x")
except socket.error, e:
print "Write gave us",e
For me, it gives:
Connect gave us (36, 'Operation now in progress')
Read gave us (35, 'Resource temporarily unavailable')
Write gave us (57, 'Socket is not connected')
These are EINPROGRESS, EAGAIN, and ENOTCONN respectively.
You are operating on a non-blocking socket, which is perfect fine to return EINPROGRESS, which indict that the connection establishment has not being finished yet, this is documented in connect's page:
EINPROGRESS
The socket is nonblocking and the connection cannot be completed immediately. It is possible to select(2) or poll(2) for completion by
selecting the socket for writing. After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET
to determine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed
here, explaining the reason for the failure).
So you will need select/pool to make sure the socket is writable, and get error from SO_ERROR.