I have input and output NSStream's as part of a TCP connection after using NSStream.getStreamsToHostWithName(). If I call the close() method on those input and output streams, then by the time the functions return, will my TCP connection be in the CLOSED state?
If not, how could I determine the time at which the underlying TCP connection actually closes?
Closing the stream terminates the flow of bytes and releases system
resources that were reserved for the stream when it was opened. If the
stream has been scheduled on a run loop, closing the stream implicitly
removes the stream from the run loop. A stream that is closed can
still be queried for its properties.
var streamStatus: NSStreamStatus { get }
The receiver’s status
enum NSStreamStatus : UInt {
case NotOpen
case Opening
case Open
case Reading
case Writing
case AtEnd
case Closed
case Error
}
As far as I can tell, the answer is no, the TCP connection will not necessarily be in the CLOSED state. To make sure the TCP connection does a graceful close and find out when that happens, one must use a lower-level API than NSStream.
Related
if I add an event for a connection socket which is returned by accept(), as below
event_set(&conn_ev, connfd, EV_READ|EV_PERSIST, on_recv, NULL);
event_base_set(base, &conn_ev);
event_add(&conn_ev, NULL);
if at sometime, the local program(not the peer) closes the socket, will the conn_ev be triggered?
if so, how to detect whether whether the event is due to the closing of the socket?
is it recv(connfd,..) returns -1 and errno is set EBAD or any other cases?
thanks!
All sockets are marked as readable if the socket is nicely closed by the other end, with read returning zero. When an error is received they are marked either read- or write-able, with read or write returning -1.
See e.g. the socket(7) manual page for a table of states.
I have two NSInputStream and NSOutputStream between devices that are connected to each other via network. When I write something in output stream, the data is written until the NSStreamEventEndEncountered event occurs. I close the output stream but on the other side (input stream) the NSStreamEventEndEncountered event never occurs, until I exit the view controller of the output stream. So:
1. Why does not the NSStreamEventEndEncountered event occurs at input stream even after the the same occurred at the output stream ? (the output stream is even closed in this event)
2. It is my understanding that, once you open the NSOutputStream, you can only write data once. Opening the output stream again after NSStreamEventEndEncountered event (for example to write something new on any event) is not possible, right ????
I probably need more info about your connection and how you're sending your data but let me try and answer your questions:
1.
You're not encountering an end of your inputstream because you never started reading from it. The outputstream finished writing because it probably encountered an end, just like you said.
Imagine Jacob (your outputstream) delivering a envelope (your data) to his friend's house. Jacob puts the envelope on his friend's doormat and walks back to his own house. At this point Jacob's work is done so he tells himself that he's done (in your case the outputstream signals an NSStreamEventEndEncountered).
Jacob's friend George (your inputstream) could see the envelope or not, but nevertheless never looks what is in it. So unless George takes the envelope and looks what is inside it, he could never tell himself that he finished looking at it (in your case the inputstream never signals an NSStreamEventEndEncountered).
2.
This actually depends on how you plan to use your outputstream. If you plan to send data multiple times to the same device, why not leave the outputstream open? You can write data as long as the socket is open and there is space available. When you close the outputstream you need to reopen it however.
am connectting the MQ with below code. I am able connected to MQ successfully. My case is i place the messages to MQ every 1 min once. After disconnecting the cable i get a ResonCode error but IsConnected property still show true. Is this is the right way to check if the connection is still connected ? Or there any best pratcices around that.
I would like to open the connection when applicaiton is started keep it open for ever.
public static MQQueueManager ConnectMQ()
{
if ((queueManager == null) || (!queueManager.IsConnected)||(queueManager.ReasonCode == 2009))
{
queueManager = new MQQueueManager();
}
return queueManager;
}
The behavior of the WMQ client connection is that when idle it will appear to be connected until an API call fails or the connection times out. So isConnected() will likely report true until a get, put or inquire call is attempted and fails, at which point QMgr will then report disconnected.
The other thing to consider here is that 2009 is not the only code you might get. It happens to be the one you get when the connection is severed but there are connection codes for QMgr shutting down, channel shutting down, and a variety of resource and other errors.
Typically for a requirement to maintain a constant connection you would want to wrap the connect and message processing loop inside a try/catch block nested inside a while statement. When you catch an exception other than an intentional exit, close the objects and QMgr, sleep at least 5 seconds, then loop around to the top of the while. The sleep is crucial because if you get caught in a tight reconnect loop and throw hundreds of connection attempts at the QMgr, you can bring even a mainframe QMgr to its knees.
An alternative is to use a v7 WMQ client and QMgr. With this combination, automatic reconnection is configurable as a channel configuration.
I have come to the point of thinking that the onWrite Event of a ClientSocket is redundant when I directly write bytes into the socket connection via SendBuf().
Is my point of thinking somewhere in the desert?
The Delphi Documentation is also somewhat bad because it just sais: "Write a routine for the onWrite event to write into the socket connection."
OnWrite is used when you're using asynchronous IO (when you have ClientType = ctNonBlocking, in other words). It's called when the socket's ready for you to send data.
Thus, your thinking's only half in the desert: if you're using ctBlocking, then don't bother with OnWrite at all. If you need that thread to send data and get on with other stuff at the same time, then use ctNonBlocking and write to the socket in OnWrite.
When you use async sockets, Windows will send your socket a CM_SOCKETMESSAGE, handled by TCustomWinSocket.CMSocketMessage. When that message has its SelectEvent property set to FD_WRITE, the OnWrite's (ultimately) invoked.
The magic ingredient here is the call to WSAAsyncSelect in TCustomWinSocket.DoSetAsyncStyles.
I have been doing overlapped serial port communication in Delphi lately and there is one problem I'm not sure how to solve.
I communicate with a modem. I write a request frame (an AT command) to the modem's COM port and then wait for the modem to respond. The event mask of the port is set to EV_RXCHAR, so when I write a request, I call WaitCommEvent() and start waiting for data to appear in the input queue. When overlapped waiting for event finishes, I immediately start reading data from the queue and read all that the device sends at once:
1) write a request
2) call WaitCommEvent() and wait until waiting finishes
3) read all the data that the device sends (not only the data being in the input queue at that moment)
4) do something and then goto 1
Waiting for event finishes after first byte appears in the input queue. During my read operation, however, more bytes appear in the queue and each of them causes an internal event flag to be set. This means that when I read all the data from the queue and then call WaitCommEvent() for the second time, it will immediately return with EV_RXCHAR mask, even though there is no data to be read.
How should I handle reading and waiting for event to be sure that the event mask returned by WaitCommEvent() is always valid? Is it possible to reset the flags of the serial port so that when I read all data from the queue and call WaitCommEvent() after then, it will not return immediately with a mask that was valid before I read the data?
The only solution that comes to my mind is this:
1) write a request
2) call WaitCommEvent() and wait until waiting finishes
3) read all the data that the device sends (not only the data being in the input queue at that moment)
4) call WaitCommEvent() which should return true immediately at the same time resetting the event flag set internally
5) do something and goto 1
Is it a good idea or is it stupid? Of course I know that the modem almost always finishes its answers with CRLF characters so I could set the comm mask to EV_RXFLAG and wait for the #10 character to appear, but there are many other devices with which I communicate and they do not always send frame end characters.
Your help will be appreciated. Thanks in advance!
Mariusz.
Your solution does sound workable. I just use a state machine to handle the transitions.
(psuedocode)
ioState := ioIdle;
while (ioState <> ioFinished) and (not aborted) do
Case ioState of
ioIdle : if there is data to read then set state to ioMidFrame
ioMidframe : if data to read then read, if end of frame set to ioEndFrame
ioEndFrame : process the data and set to ioFinished
ioFinished : // don't do anything, for doc purposes only.
end;