Symbian OS Communications (779884), страница 33
Текст из файла (страница 33)
When theConnect() returns, a link will have been established or an error will besignalled.CIrOutboundConnection : public CActive{enum TState{EDiscoveringDeviceAndService,EConnectingSocket};public:...void ConnectSocketL();virtual void RunL();...private:RSocketServ iSs;RSocket iSocket;TIrdaSockAddr iAddr;TUint8 iPort;TState iState;};void CIrOutboundConnection::ConnectSocketL(){iState = EDiscoveringDeviceAndService;User::LeaveIfError(ss.Open());// Open an IrDA socketUser::LeaveIfError(socket.Open(ss, KIrdaAddrFamily, KSockSeqPacket,KIrTinyTP));// Run device discovery, connect to IAS, and find port.// Return port and device addresses in the supplied parameters.DiscoverDeviceAndService(iAddr, iPort, iStatus);SetActive();}void CIrOutboundConnection::RunL(){if (iStatus.Int() == KErrNone){146INFRAREDswitch (iState){case EDiscoveringDeviceAndService:iState = EConnectingSocket;// Build a complete TIrdaSockAddr from discovery// results.
We could have made DiscoverDevice... function// return the address and port precombined, but chose not// to illustate the two parts of the addressiAddr.SetRemotePort(iPort);// Open connectionsocket.Connect(iAddr, iStatus);SetActive();return;case EConnectingSocket:// Now connected to remote device.break;}}else{User::LeaveIfError(status.Int());}Example 5.7Connecting to a remote deviceDiscoverDeviceAndService() is not shown, but is a combination of the device discovery and service search functionality we’ve alreadyseen.Now we’ve seen how to connect an outbound socket, we’ll look atcreating inbound (a.k.a. server) sockets.5.3.9 Server SocketsRunning an IrDA server on Symbian OS requires a ‘server’ or ‘listening’socket.
This socket provides an endpoint which a remote device mayconnect to, and so exchange data.As with all listening sockets, the sequence is: open the socket, bindto the desired local port, listen for connections, and finally issue anasynchronous Accept() call. The general framework has already beencovered in chapter 3, so this section will only deal with the IrDA specializations.Opening a socket is exactly the same as for outgoing connections,and uses the same parameters.
Once the socket has been opened, thenext step is binding to a local LSAP SEL. Due to the limited range ofvalues available, it is more likely that a port will already be in use ifhard-coded (or ‘well-known’) values are used. As IrDA provides the IASdatabase to discover channel identifiers, it is strongly recommended thatyou allow the stack to select an appropriate LSAP SEL for your application. An invalid LSAP SEL constant is provided in ir_sock.h for thispurpose – binding to KAutoBindLSAP will lead to the stack selecting theIRDA IN SYMBIAN OS147lowest numbered unused LSAP SEL. A call to RSocket::LocalName()will retrieve the selected port, after which point you can register yourservice in the IAS database, as described previously in ‘5.3.6 Serviceregistration’.As a final point to note when dealing with listening sockets, acceptqueue sizes greater than one have not been extensively tested.
Whilst theIrDA protocols and the Symbian stack should handle multiple simultaneous connections to the same local LSAP SEL, for maximum reliability itis recommended that this is not relied upon.class CIrInboundConnection : public CActive{enum TState{ERegisteringService,EListening};public:...void StartListeningL();virtual void RunL();...private:RSocketServ iSs;RSocket iListener;RSocket iAcceptor;TUint8 iPort;TState iState;};void CIrInboundConnection::StartListeningL(){iState = ERegisteringService;User::LeaveIfError(ss.Open());// Open an IrDA socketUser::LeaveIfError(iListener.Open(ss, KIrdaAddrFamily, KSockSeqPacket,KIrTinyTP));// Create a TIrdaSockAddrTIrdaSockAddr addr;addr.SetLocalPort(KAutoBindLSAP);// Bind to portUser::LeaveIfError(iListener.Bind(addr));// Start listeningUser::LeaveIfError(iListener.Listen(1));// Register service in IASUser::LeaveIfError(iListener.LocalName(addr));iPort = addr.GetHomePort();RegisterThisService(iPort, iStatus);SetActive();}148INFRAREDvoid CIrInboundConnection::RunL(){if (iStatus.Int() == KErrNone){switch (iState){case ERegisteringService:iState = EListening;// Wait for a connectionlistener.Accept(iAccepting, iStatus);SetActive();return;case EListening:// do something with newly connected socket!// eg.
iSomeInterface.NewConnection(iAccepting);// Wait for the next connectionlistener.Accept(iAccepting, iStatus);SetActive();}}else{User::Leave(iStatus.Int());}}Example 5.8Listening for an incoming connectionAgain, we have not shown RegisterThisService() but it canbe easily created based on the earlier examples. Neither have weshown where connected sockets are used, beyond the comment aboutiSomeInterface in the comment on the EListening case, as this isalso application-specific detail.5.3.10 Reading and WritingReading and writing data over IrDA sockets is performed exactly as withany other datagram-based sockets.
The major point to note is that evenTinyTP only exposes a datagram interface – there is no stream support.As a result of this, datagram boundaries are respected, and so wholedatagram reads must normally be queued. However, ESOCK does have asystem known as datagram read continuation, which allows partial readson datagram protocols. This is achieved by passing KSockReadContinuation into the Recv() call in the flags parameter – see chapter 3for full details.Two socket options are also useful here: KHostMaxDataSizeOptand KRemoteMaxDataSizeOpt allow discovery of the packet size inuse on the link. Incoming datagrams will never be larger than this, soreads of KHostMaxDataSizeOpt size will never lose data, or requirethe use of read continuations.
Some devices limit the packet size – theIrDA protocols allow for a range of sizes up to 2048 bytes.IRDA IN SYMBIAN OS149Similarly to reads, writes must also respect datagram boundaries. Inthe case of writes, this means not asking the stack to send more datathan KRemoteMaxDataSizeOpt. This means that fragmentation of largepackets must be performed by the application, as the stack will refuse tosend such datagrams.There is one situation where larger packets than the transport packetsize may be sent – when using TinyTP segmentation and reassembly. Thisis a little-used feature of TinyTP which allows a single datagram to be segmented across a number of LM-MUX datagrams, and then reassembled onreception.
The reason that it is rarely used is that a number of implementations have contained defects, so causing interoperability problems. ASymbian OS socket option, KTinyTPDisabledSegmentation, existsto force the stack to ignore requests to reassemble datagrams – this mayhelp when running against stacks which ignore the maximum buffer sizefor reassembly advertised by the host. The data received is still valid, apartfor the additional datagram boundaries, however this can cause seriousproblems if your application relies on the framing of TinyTP to provide adatagram interface as you will no longer be able to determine where the‘real’ datagram boundaries are.
It is recommended that you always setthis socket option unless you need the framing provided by TinyTP.5.3.11 Socket OptionsThese options may be passed to RSocket::SetOpt(), in order toprompt the stack to perform a variety of actions. Unless otherwiseindicated, all of these calls require the LocalServices capability.KUnexpeditedDataOptKExpeditedDataOptUse expedited data packets to carry the data. These data packets aretransferred in IrLAP UI frames, which exempts them from reliable delivery.They are also transmitted in preference to non-expedited packets, and onthe receiver side will short-circuit queues. As a result, using these packetsbreaks in-order delivery.
There is no way to know that a particular packetreceived by a remote device was transmitted as an expedited packet, andno requirement on a receiver to agree to handle such packets.Unlike the other socket options, the two options above may only beused on individual socket writes – rather than in a call to SetOpt().KDiscoverySlotsOptSets the number of discovery slots to use when running a discoverysequence.