On 27 Mar 2013, at 10:55, Norbert Hartl <norb...@hartl.name> wrote: > > Am 27.03.2013 um 00:25 schrieb Sven Van Caekenberghe <s...@stfx.eu>: > >> >> On 26 Mar 2013, at 23:46, Norbert Hartl <norb...@hartl.name> wrote: >> >>> Am 26.03.2013 um 21:08 schrieb Sven Van Caekenberghe <s...@stfx.eu>: >>> >>>> Hi Holger, >>>> >>>> On 26 Mar 2013, at 12:12, Holger Hans Peter Freyther <hol...@freyther.de> >>>> wrote: >>>> >>>>> Hi, >>>>> >>>>> I am porting a tooling class that I wrote on GST for my SIP and MGCP code >>>>> to Pharo. This class will create a socket and then fork a RX and TX >>>>> process. >>>>> I have some issues with 'stopping' the socket. I have created an example >>>>> that shows the issue in Pharo 2.0 and Pharo 1.4 with the pharovm (and to >>>>> have more debug output with a re-compiled one). >>>>> >>>>> >>>>> | s rx | >>>>> s := Socket newUDP. >>>>> rx := [ >>>>> [s waitForData. s halt] >>>>> on: ConnectionClosed do: [ s halt] >>>>> ] fork. >>>>> "Wait for the process to hit the readSemaphore" >>>>> (Delay forSeconds: 3) wait. >>>>> s close. >>>>> >>>>> >>>>> My expectation is that I will get the ConnectionClosed signal or at least >>>>> that >>#waitForData will return once the socket is closed. This is based >>>>> on reading the comment of >>#waitForData. >>>>> >>>>> >>>>> The Socket>>#waitForData documentation reads like this: >>>>> "Wait for data to arrive. This method will block until >>>>> data is available or the socket is closed. If the socket is closed >>>>> a ConnectionClosed exception will be signaled." >>>>> >>>>> >>>>> I had a look at the socket plugin and the following is happening. First >>>>> aio is disabled, the state set to ThisEndClosed, then ::close is called >>>>> and in the above case the result is '0' and the following code will be >>>>> executed: >>>>> >>>>> else if (0 == result) >>>>> { >>>>> /* close completed synchronously */ >>>>> SOCKETSTATE(s)= Unconnected; >>>>> FPRINTF((stderr, "closeConnection: disconnected\n")); >>>>> SOCKET(s)= -1; >>>>> } >>>>> >>>>> >>>>> this means that my 'rx' process will happily wait on the readSemaphore >>>>> of the Socket and will never be woken up. >>>>> >>>>> >>>>> My question are probably: >>>>> >>>>> 1.) Is this the intended behavior for Socket>>#close and >>>>> Socket>>#waitForData? >>>>> 2.) How should I terminate my RX process? >>>>> >>>>> kind regards >>>>> holger >>>>> >>>>> PS: The issue is probably socket specific and not related to UDP. >>>> >>>> Maybe I am telling you things you already know, but TCP and UDP are >>>> fundamentally different. UDP is really one-shot, try-and-hope, completely >>>> asynchronous. In networking you generally only get a ConnectionClosed when >>>> you actually read or write (and even then ;-). >>>> >>> That's not really true. It is implementation specific. IMHO you can open a >>> UDP socket in send and receive mode where the communication is synchronous. >>> So your socket blocks until a datagram socket is received. This has to >>> advantage that the underlying OS registers local and remote port and >>> automatically and accepts only datagrams for the right ports match. As it >>> is in a lot of use cases not preferrable to have blocking sockets while >>> using UDP you use two sockets instead, one for sending and one for >>> receiving. For this you need to register the listening socket for listening >>> to everything. >>> Disclaimer: I took this from the back of my head and this might by >>> outdated/inproper information. I just wanted to say that you shouldn't mix >>> asynchronous with unidirectional :) >>> >>> Norbert >> >> I politely disagree ;-) >> >> But I am willing to learn: so please provide some references of such UDP >> usage. >> >> http://en.wikipedia.org/wiki/Datagram >> > If I find the time I dig out some things from the past. I just can't follow > your reasoning that the way UDP is defined means unidirectional. TCP defines > a connection, UDP does not. Connections are not required to have end-to-end > communication. A remote port is a service identifier and local port is a > client identifier. A port pair defines a communication channel. TCP just adds > roles to both ends and defines stream sequences and transmission windows. > Maybe I misunderstood you then I take everything back :)
It is probably about terms and how we each interpret them. I was not trying to be very formal, maybe that was confusing. Some of the terms you are using are not my standard vocabulary. But I don't think I said 'unidirectional' in any sentence. Here is my non-formal high-level description: A datagram (UDP packet) is a (small) collection of bytes being sent from A to B. Either A or B can be client/server, or sender/receiver. To receive or to be server, you have to be bound to a port (or you listen on the default port assigned to you when sending). Datagrams know their length and sender/destination host:port - but that is mostly implementation. Semantically, datagrams can get lost or arrive out of order. A or B will never know as there are no guarantees. To add reliability, you need acknowledgements, retries, numbering, and so on. If you do all that with a stream interface, you are building your own TCP layer. As a (Smalltalk) user, that means that #sendUDPData:toHost:port: will not tell you if anything is wrong, for example Socket newUDP sendUDPData: #[ 1 2 3 ] toHost: #[ 217 11 221 200 ] port: 12345 sending 3 bytes to pharo.st:12345 will give no error at all #receiveUDPDataInto: will either return a datagram or not, but does not signal any error it will also return immediately, so you have to loop BTW, these are not necessarily disadvantages, but advantages to build specific, efficient, low-level protocols. Sven > Norbert > >>>> The Socket API has many strange methods, most of which you should not >>>> touch. You should use SocketStream. Looking in the VM code is also >>>> misleading because the 3 platforms (Mac, Win, *nix) are different. In >>>> Socket[Stream] there is lots of historic baggage. >>>> >>>> I would suggest you look at Smalltalk code that actually works (for TCP, >>>> Zinc Client and Server code would do, for UDP, ZTimestampSNTPClient for >>>> example). >>>> >>>> For your concrete question (2): just start a reading process, wrap it in a >>>> handler and clean up. For UDP this will never happen: you will keep on >>>> reading nothing. For TCP reading will eventually fail if the other end >>>> disappears. >>>> >>>> HTH, >>>> >>>> Sven >>>> >>>> -- >>>> Sven Van Caekenberghe >>>> http://stfx.eu >>>> Smalltalk is the Red Pill >>>> >>>> >>> >>> >> >> > >