NetworkStream Read. Please explain behavior - networkstream

I am writing a client program using NetworkStream. This question is somehow related to Networkstream read is blocking
My question is: What is exactly the behaviour of NetworkStream read?
I have googled, and read microsoft documentation and my findings don't agree with what I found.
1) First I read that it was blocking. Ergo I thought if something happens to the server, it will wait for the server connect again and a message to arrive. But this is not true. When the server gets disconnected , it throws an exception.
2) Related to that, will read ever return "0 bytes read"? How? What does this exactly means?
3) Should I use the catch to retry connection or should I use the "data available" property?
Thanks for any help you can give me.

Related

Trying to send a FIX api message to ctrader server using Ruby but receiving no response

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.

ZeroMQ: How to initialize a SUB and PUSH socket in same code? i.e. black box pattern but not using different machines

I have this code
context = zmq.Context()
app_worker = context.socket(zmq.PUSH)
app_worker.bind("tcp://127.0.0.1:9005")
app_sub = context.socket(zmq.SUB)
app_sub.connect("tcp://127.0.0.1:9004")
app_sub.setsockopt(zmq.SUBSCRIBE,'sometopic')
while True:
msg = app_sub.recv()
msg_data = msg.split(' ',1)
app_worker.send_json(msg_data[1])
print msg_data[1]
but when i run this, it is unable to receive any message from the publisher but when i comment this lines
app_worker = context.socket(zmq.PUSH)
app_worker.bind("tcp://127.0.0.1:9005")
it suddenly works. it is stated in the zeromq guide chapter 5 black box pattern that this is possible. if so, what am i doing wrong here?
You didn't supply enough data to solve this question with 100% assurances.
But based on what you did post the most obvious problem is that the port 9005 was already binded by someone else.
Its very likely your app_worker.send_json(msg_data[1]) is blocking (the entire thread) if there are no downstream nodes to PULL the messages.
Set the send_json to non blocking mode and check the error/exception returned
app_worker.send_json(msg_data[1], zmq.NOBLOCK)
The reason it "works" when you comment out the bind is because the send is just failing and not blocking.

APNs error handling in ruby

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.

Boost async_receive_from makes std::cin crash with buffer overflow

while coding a server supporting both TCP and UDP with the boost library, I encountered a strange problem: After the server receives any UDP message, a call of std::cin (or std::getline) will crash if I try to put the input into a string.
This does only happen after at least one UDP message was received. I have no idea what happens here, because I hardly do anything when receiving a message. I broke the important code down:
void AsynchronousServer::DoReceiveUDP()
{
m_udp_socket.async_receive_from(boost::asio::buffer(m_udp_receive_buffer,
m_udp_receive_buffer.size()),
udp::endpoint(), [this](boost::system::error_code error, std::size_t
bytes_transferred)
{
});
}
The DoReceiveUDP() method is called right when the server is up and before io_service.run(). Usually it does a bit more (e.g. call itself again), but for testing purposes I commented everything out so that it really does nothing more than receive once. m_udp_receive_buffer is an
std::array<char, 8196>
, an attribute of the AsynchronousServer class that is not used anywhere else.
In the main thread, this is all I really do after setting up the server:
while(true)
{
std::string message;
std::getline(std::cin, message); //On this line the program crashes
//server.SendMessageTCP(1, message);
}
Now as I said, the crash (debug message says buffer overflow) only happens after a message was received via UDP. My server also reads TCP messages via async_read. This does not provoke the error though.
I also tested this with storing the getline-input in an constant sized array, which works fine. But I cant really do that since I dont know how long the message is then, which means the buffer is filled with a lot of useless characters when I send the message. Besides, I dont really feel safe anyway with strange stuff like that happening and would rather solve the problem than bypass it.
Do any of you have some ideas on what could be the problem here? If you need more code, just ask, but I think I already posted everything relevant. :)
EDIT: I commented out the error code and bytes transferred too, but it is in the "full" version. I don't get any errors and bytes transferred is exactly the length of the message.
After some more tests I can at least guess a little more. The problem seems to occur if I am expected to enter input via cin and during this, a message is received.
E.g. if I do this:
while(true)
{
std::string message;
boost::this_thread::sleep(boost::posix_time::seconds(3));
std::getline(std::cin, message);
}
and the client sends a UDP message within this three seconds the thread sleeps, everything goes fine. If the three seconds pass and THEN the message is received, it crashes as before.
However, there is one really strange behaviour: After I sended a UDP message within these three seconds, the program won't crash anymore at all - even if I wait with the next message until the thread has reached getline again. I have no idea why that happens...
Alright so I found a "solution" for this problem. I still don't know why it happens and if that is really a solution at all or whether I'll run into other problems later.
Also, I have no idea, why this solution works. :D
Anyway, it works if the buffer is not a member function but created anew for every call of ReceiveUDP:
void AsynchronousServer::DoReceiveUDP()
{
std::shared_ptr<std::array<char, 8192>> udp_receive_buffer;
m_udp_socket.async_receive_from(boost::asio::buffer(*udp_receive_buffer, udp_receive_buffer->size()),
udp::endpoint(), boost::bind<void>([this](boost::system::error_code error, std::size_t bytes_transferred,
std::shared_ptr<std::array<char, 8192>> udp_receive_buffer)
{
}, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, udp_receive_buffer));
}

What is JDBC's Connection.isClosed() good for, and why is Snaq DBPool misbehaving on close?

I have the following code in Java:
if(!conn.isClosed())
{
conn.close();
}
Instead of working, I am awarded with:
java.sql.SQLException: Connection already closed
My connection object is a Snaq.db.CacheConnection
I checked the JavaDocs for isClosed, and they state that:
This method generally cannot be called
to determine whether a connection to a
database is valid or invalid. A
typical client can determine that a
connection is invalid by catching any
exceptions that might be thrown when
an operation is attempted.
So my questions are:
1) What good is JDBC's isClosed() anyway? Since when do we use Exceptions in Java to check for validity?
2) What is the correct pattern to close a database? Should I just close and swallow exceptions?
3) Any idea why would SnaqDB be closing the connection? (My backend is a Postgres 8.3)
I'll answer your questions with corresponding numbers:
I agree with you, it seems strange that isClosed provides the closed state only on a best effort basis, and that your code still has to be prepared to catch the exception when closing the connection. I think the reason is that the connection may be closed at any time by the database, and so any status returned by a query state method like isClosed is intrinsicly stale information - the state may change between checking isClosed and calling close on the Connection.
Calling close has no affect on your data and on previous queries. JDBC operations execute with synchronous results, so all useful execution has either succeeded or failed by the time isClosed is called. (True with both autoCommit or explicit transaction boundaries.) If your application is a single user accessing a local database, then perhaps showing the error to the user might help them diagnose problems. In other environments, logging the exception and swallowing it is probably the best course of action. Either way, swallowing the excpetion is safe, as has no bearing on the state of the database.
Looking at the source for SnaqDB CacheConnection, the isClosed method delegates to the underlying connection. So the problem is not there, but lies with the defined contract for isClosed() and Connection.close() throwing an exception.

Resources