Symbian OS Communications (779884), страница 10
Текст из файла (страница 10)
By default the send operation will block if a buffer isn’t available forthe data. This can be overridden by calling RSocket::Ioctl()with KSoNonBlockingIO (see ‘Ioctls and options’ below), but firstread the previous advice on non-blocking I/O, i.e., this isn’t actuallya problem unless your application expects to get a response to its callwithin a ‘short’ time. Symbian OS applications using active objectsfor socket operations in conjunction with the socket API methodsthat take TRequestStatus& parameters can happily ‘block’ on asocket call as they can still do other useful work in the meantime.4. For a datagram or sequenced packet socket, if the amount of datapassed in the descriptor passed is larger than the maximum outbounddata size then the send will be errored with KErrTooBig, and nodata will be sent.As you would expect, an outstanding Send() or SendTo() operationcan be cancelled using CancelSend(), and an outstanding Write()operation can be cancelled using CancelWrite().
Of course, cancelling a send doesn’t necessarily mean that the data won’t be sent: thesend processing by the protocol is asynchronous with respect to your program, so your program may have called cancel as the protocol is busilysending the data out onto the link, before it processes the cancellationrequest.Receiving dataReceiving data is done using the following methods:void Recv(TDes8& aDesc,TUint flags,TRequestStatus& aStatus);void Recv(TDes8& aDesc,TUint flags,TRequestStatus& aStatus,TSockXfrLength& aLen);void RecvOneOrMore(TDes8& aDesc,TUint flags,TRequestStatus& aStatus,TSockXfrLength& aLen);void Read(TDes8& aDesc,TRequestStatus& aStatus);void RecvFrom(TDes8& aDesc,TSockAddr& anAddr,TUint flags,TRequestStatus& aStatus);void RecvFrom(TDes8& aDesc,TSockAddr& anAddr,TUint flags,TRequestStatus& aStatus,TSockXfrLength& aLen);void CancelRecv();void CancelRead();2We often see requests from developers asking for a way to find out if their data hasreached the remote device yet.
Our advice is always to incorporate a method into yourprotocol to do this. Even if it were possible to detect that the remote device has received thedata (e.g., tracking acknowledged sequence numbers in connection-based protocols) that’sno guarantee that the data has got to the application at the other end yet – it could justbe sitting around in a buffer somewhere waiting to be read. And there’s still no guaranteethe remote system isn’t going to crash before the application at that end reads it! So eitheraccept that the service is best-effort from the moment you pass the data into the socket, ordevelop some form of response to the request you make, e.g., HTTP uses response codes toindicate that it has received and processed a request.40AN INTRODUCTION TO ESOCKThe first distinction is between Recv() and RecvFrom().Recv() is used with connected sockets, and RecvFrom() with connectionless sockets.
Otherwise they are identical, so let’s focus on Recv()in this discussion.Recv() provides the ability to receive a certain amount of datafrom the peer. The length of the data to be received is specified bythe maximum length of the descriptor (not the current length of thedescriptor).
On completion the descriptor’s length is set to the length ofthe data received.Warning: if passing an HBufC to the Recv() method, be aware thatthe maximum length of the allocated HBufC may be greater thanwhat was requested in the NewL() or ReAllocL(), which will causeRecv() to wait for more data than might be expected. To avoid this,wrap a TPtr of the right length over the HBufC and pass that to theRecv() call, or consider using RBuf.As with the Send() calls above, there is the option to pass flagsto modify how the Recv() is performed. The only generic option isKSIPeekData (if the protocol supports it), which returns the data butleaves the data in the socket’s buffers, so the next read will return the samedata.
This can be useful if the incoming data consists of a known-lengthheader with an unknown amount of extra data specified by a length fieldin the header. By first reading the header with KSIPeekData, the lengthof the extra data can be read out while leaving the header informationin the socket buffers. Then you can provide a descriptor large enoughto fit the whole message into and read the whole message including theheader with a single Recv() call. This avoids the need to write code tomanage reassembling the whole message from multiple Recv() calls.The Recv() calls return when a packet is received for datagram orseqpacket sockets, or when the descriptor is full for stream sockets (see‘Types of sockets’ above).Warning: With a datagram or sequenced packet socket, you can losedata if the descriptor passed into Recv() is smaller than the incomingpacket – the overflowing data is thrown away.
This can be preventedby passing the KSockReadContinuation flag to Recv(), whichmodifies the behavior so that the next receive call will return theoverflow data. See details in the Symbian OS Library for how this works.This leads to a problem with stream sockets as it is impossible to knowhow much data the peer will send, so the Recv() call could blockOVERVIEW OF ESOCK41indefinitely. There are two ways round this: using non-blocking I/O orusing RecvOneOrMore().Non-blocking I/O is enabled by using an ioctl (see ‘Ioctls and options’in the next section), in which case the Recv() call will return KErrWouldBlock if there isn’t enough data available to fill the descriptor.Alternatively, RecvOneOrMore() will return immediately if there is dataavailable, filling as much of the descriptor as there is data.
If there isn’tany data waiting, the call blocks until data comes in.Of the two, RecvOneOrMore() is more likely to be what you’llneed – with non-blocking I/O, if there’s no data waiting then the callreturns immediately. There’s then no way to know when data has arrivedfrom the remote peer without repeatedly calling Recv(), that is polling.Polling is inherently evil in a portable battery-powered device as itprevents the system going to lower power modes, and hence reducesbattery life. Neither does the use of non-blocking I/O fit well with thestandard Symbian asynchronous programming model, that is the use ofactive objects, which essentially provide non-blocking I/O via an alternatemechanism that also removes the need for polling.Incidentally, the TSockXfrLength parameter is only useful whenusing the KSockReadContinuation flag.
Otherwise, in all these callsthe length of the descriptor is always set to the length of the data returned.In the case of using read continuations with a datagram or sequencedpacket protocol, it indicates the number of bytes remaining in the currentdatagram, to allow an appropriately-sized buffer to be passed in on thenext read to pick up the remaining part of the packet.Read() provides a simplified interface to Recv() when you don’tneed to pass flags.An ongoing Recv() and Read() can be cancelled using CancelRecv() or CancelRead() respectively.Ioctls and options In addition to the send/recv calls for data transfer, thesockets API provides three ways to control the socket’s behavior and/orretrieve information:TInt SetOpt(TUint anOptionName,TUint anOptionLevel,const TDesC8& anOption=TPtrC8(NULL,0));TInt SetOpt(TUint anOptionName,TUint anOptionLevel,TInt anOption);TInt GetOpt(TUint anOptionName,TUint anOptionLevel,TDes8& anOption);TInt GetOpt(TUint anOptionName,TUint anOptionLevel,TInt& anOption);void Ioctl(TUint aCommand,TRequestStatus& aStatus,TDes8* aDesc=NULL,TUint aLevel=KLevelUnspecified);GetOpt()/SetOpt() are used to synchronously read and write various socket options.
There are some generic socket options implementedby ESOCK, and each protocol may provide additional protocol-specificoptions. For ESOCK options, the level is set to KSOLSocket. For protocolspecific options the protocol defines various levels.42AN INTRODUCTION TO ESOCKThe generic options provided by ESOCK are shown in Table 3.3.Ioctls provide an asynchronous command channel to a socket that canbe used for operations that may take a long time.
ESOCK provides onegeneric ioctl: KIOctlSelect, which provides a functionality similarto the Unix select() call. Protocol-specific ioctls are documentedin the Symbian OS Developer Library under the respective protocol.Outstanding ioctls can be cancelled using CancelIoctl().Disconnecting A connected socket can be disconnected using Shutdown(). While simply closing the socket will also disconnect anyconnection, the difference is that Shutdown() is asynchronous whileClose() is synchronous. If the disconnection takes time, the Close()call will block until it is complete – this is unlikely to be what you wantin your application. The Shutdown() methods are:void Shutdown(TShutdown aHow,TRequestStatus& aStatus);void Shutdown(TShutdown aHow,const TDesC8& aDisconnectDataOut,TDes8& aDisconnectDataIn,TRequestStatus& aStatus);Note that connected socket here means that the protocol is aconnection-oriented one (i.e., it doesn’t have the KSIConnectionLess flag set), it is not simply a socket on which Connect() has beencalled.The TShutdown parameter specifies how the connection is to beclosed.