QNativeSocketEngine Class
The QNativeSocketEngine class provides low level access to a socket. More...
Header: | #include <QNativeSocketEngine> |
Inherits: | QAbstractSocketEngine |
Public Functions
QNativeSocketEngine(QObject *parent = nullptr) | |
virtual | ~QNativeSocketEngine() |
Reimplemented Public Functions
virtual qintptr | accept() override |
virtual bool | bind(const QHostAddress &address, quint16 port) override |
virtual qint64 | bytesAvailable() const override |
virtual void | close() override |
virtual bool | connectToHost(const QHostAddress &address, quint16 port) override |
virtual bool | connectToHostByName(const QString &name, quint16 port) override |
virtual bool | hasPendingDatagrams() const override |
virtual bool | initialize(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol) override |
virtual bool | initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState) override |
virtual bool | isValid() const override |
virtual bool | joinMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface) override |
virtual bool | leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface) override |
virtual bool | listen(int backlog) override |
virtual QNetworkInterface | multicastInterface() const override |
virtual int | option(SocketOption socketOption) const override |
virtual qint64 | pendingDatagramSize() const override |
virtual qint64 | read(char *data, qint64 maxSize) override |
virtual qint64 | readDatagram(char *data, qint64 maxSize, QIpPacketHeader *header = nullptr, PacketHeaderOptions options = WantNone) override |
virtual bool | setMulticastInterface(const QNetworkInterface &iface) override |
virtual bool | setOption(SocketOption option, int value) override |
virtual qintptr | socketDescriptor() const override |
virtual bool | waitForRead(int msecs = 30000, bool *timedOut = nullptr) override |
virtual bool | waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override |
virtual qint64 | write(const char *data, qint64 size) override |
virtual qint64 | writeDatagram(const char *data, qint64 size, const QIpPacketHeader &header) override |
Public Slots
void | connectionNotification() |
Detailed Description
\internal
\reentrant
\ingroup
network \inmodule
QtNetwork
QtSocketLayer provides basic socket functionality provided by the operating system. It also keeps track of what state the socket is in, and which errors that occur.
The classes QTcpSocket, QUdpSocket and QTcpServer provide a higher level API, and are in general more useful for the common application.
There are two main ways of initializing the a QNativeSocketEngine; either create a new socket by passing the socket type (TcpSocket or UdpSocket) and network layer protocol (IPv4Protocol or IPv6Protocol) to initialize(), or pass an existing socket descriptor and have QNativeSocketEngine determine the type and protocol itself. The native socket descriptor can later be fetched by calling socketDescriptor(). The socket is made non-blocking, but blocking behavior can still be achieved by calling waitForRead() and waitForWrite(). isValid() can be called to check if the socket has been successfully initialized and is ready to use.
To connect to a host, determine its address and pass this and the port number to connectToHost(). The socket can then be used as a TCP or UDP client. Otherwise; bind(), listen() and accept() are used to have the socket function as a TCP or UDP server. Call close() to close the socket.
bytesAvailable() is called to determine how much data is available for reading. read() and write() are used by both TCP and UDP clients to exchange data with the connected peer. UDP clients can also call hasMoreDatagrams(), nextDatagramSize(), readDatagram(), and writeDatagram().
Call state() to determine the state of the socket, for example, ListeningState or ConnectedState. socketType() tells whether the socket is a TCP socket or a UDP socket, or if the socket type is unknown. protocol() is used to determine the socket's network layer protocol.
localAddress(), localPort() are called to find the address and port that are currently bound to the socket. If the socket is connected, peerAddress() and peerPort() determine the address and port of the connected peer.
Finally, if any function should fail, error() and errorString() can be called to determine the cause of the error.
Member Function Documentation
QNativeSocketEngine::QNativeSocketEngine(QObject *parent = nullptr)
Constructs a QNativeSocketEngine.
See also initialize().
[virtual noexcept]
QNativeSocketEngine::~QNativeSocketEngine()
Destructs a QNativeSocketEngine.
[override virtual]
qintptr QNativeSocketEngine::accept()
Accepts a pending connection from the socket, which must be in ListeningState, and returns its socket descriptor. If no pending connections are available, -1 is returned.
[override virtual]
bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port)
Binds the socket to the address address and port port. Returns true
on success; otherwise false is returned. The port may be 0, in which case an arbitrary unused port is assigned automatically by the operating system.
Servers call this function to set up the server's address and port. TCP servers must in addition call listen() after bind().
[override virtual]
qint64 QNativeSocketEngine::bytesAvailable() const
Returns the number of bytes that are currently available for reading. On error, -1 is returned.
For UDP sockets, this function returns the accumulated size of all pending datagrams, and it is therefore more useful for UDP sockets to call hasPendingDatagrams() and pendingDatagramSize().
[override virtual]
void QNativeSocketEngine::close()
Closes the socket. In order to use the socket again, initialize() must be called.
[override virtual]
bool QNativeSocketEngine::connectToHost(const QHostAddress &address, quint16 port)
Connects to the IP address and port specified by address and port. If the connection is established, this function returns true
and the socket enters ConnectedState. Otherwise, false is returned.
If false is returned, state() should be called to see if the socket is in ConnectingState. If so, a delayed TCP connection is taking place, and connectToHost() must be called again later to determine if the connection was established successfully or not. The second connection attempt must be made when the socket is ready for writing. This state can be determined either by connecting a QSocketNotifier to the socket descriptor returned by socketDescriptor(), or by calling the blocking function waitForWrite().
Example:
QNativeSocketEngine socketLayer; socketLayer.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol); socketLayer.connectToHost(QHostAddress::LocalHost, 22); // returns false socketLayer.waitForWrite(); socketLayer.connectToHost(QHostAddress::LocalHost, 22); // returns true
Otherwise, error() should be called to determine the cause of the error.
[override virtual]
bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port)
Connects to the remote host name given by name on port port. When this function is called, the upper-level will not perform a hostname lookup.
The native socket engine does not support this operation, but some other socket engines (notably proxy-based ones) do.
[slot]
void QNativeSocketEngine::connectionNotification()
If there's a connection activity on the socket, process it. Then notify our parent if there really was activity.
[override virtual]
bool QNativeSocketEngine::hasPendingDatagrams() const
Returns true
if there is at least one datagram pending. This function is only called by UDP sockets, where a datagram can have a size of 0. TCP sockets call bytesAvailable().
[override virtual]
bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol)
Initializes a QNativeSocketEngine by creating a new socket of type socketType and network layer protocol protocol. Returns true
on success; otherwise returns false
.
If the socket was already initialized, this function closes the socket before reeinitializing it.
The new socket is non-blocking, and for UDP sockets it's also broadcast enabled.
[override virtual]
bool QNativeSocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState)
This is an overloaded function.
Initializes the socket using socketDescriptor instead of creating a new one. The socket type and network layer protocol are determined automatically. The socket's state is set to socketState.
If the socket type is either TCP or UDP, it is made non-blocking. UDP sockets are also broadcast enabled.
[override virtual]
bool QNativeSocketEngine::isValid() const
Returns true
if the socket is valid; otherwise returns false
. A socket is valid if it has not been successfully initialized, or if it has been closed.
[override virtual]
bool QNativeSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface)
\since
4.8
[override virtual]
bool QNativeSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface)
\since
4.8
[override virtual]
bool QNativeSocketEngine::listen(int backlog)
Prepares a TCP server for accepting incoming connections. This function must be called after bind(), and only by TCP sockets.
After this function has been called, pending client connections are detected by checking if the socket is ready for reading. This can be done by either creating a QSocketNotifier, passing the socket descriptor returned by socketDescriptor(), or by calling the blocking function waitForRead().
Example:
QNativeSocketEngine socketLayer; socketLayer.bind(QHostAddress::Any, 4000); socketLayer.listen(); if (socketLayer.waitForRead()) { int clientSocket = socketLayer.accept(); // a client is connected }
[override virtual]
QNetworkInterface QNativeSocketEngine::multicastInterface() const
\since
4.8
See also setMulticastInterface().
[override virtual]
int QNativeSocketEngine::option(SocketOption socketOption) const
Returns the value of the option socketOption.
See also setOption().
[override virtual]
qint64 QNativeSocketEngine::pendingDatagramSize() const
Returns the size of the pending datagram, or -1 if no datagram is pending. A datagram size of 0 is perfectly valid. This function is called by UDP sockets before receiveMessage(). For TCP sockets, call bytesAvailable().
[override virtual]
qint64 QNativeSocketEngine::read(char *data, qint64 maxSize)
Reads up to maxSize bytes into data from the socket. Returns the number of bytes read, or -1 if an error occurred.
[override virtual]
qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxSize, QIpPacketHeader *header = nullptr, PacketHeaderOptions options = WantNone)
Reads up to maxSize bytes of a datagram from the socket, stores it in data and returns the number of bytes read. The address, port, and other IP header fields are stored in header according to the request in options.
For UDP sockets, to avoid unnecessarily loss of data, call pendingDatagramSize() to determine the size of the pending message before reading it. If maxSize is too small, the rest of the datagram will be lost.
Returns -1 if an error occurred.
See also hasPendingDatagrams().
[override virtual]
bool QNativeSocketEngine::setMulticastInterface(const QNetworkInterface &iface)
\since
4.8
See also multicastInterface().
[override virtual]
bool QNativeSocketEngine::setOption(SocketOption option, int value)
Sets the option option to the value value.
See also option().
[override virtual]
qintptr QNativeSocketEngine::socketDescriptor() const
Returns the native socket descriptor. Any use of this descriptor stands the risk of being non-portable.
[override virtual]
bool QNativeSocketEngine::waitForRead(int msecs = 30000, bool *timedOut = nullptr)
Waits for msecs milliseconds or until the socket is ready for reading. If timedOut is not nullptr
and msecs milliseconds have passed, the value of timedOut is set to true.
Returns true
if data is available for reading; otherwise returns false.
This is a blocking function call; its use is disadvised in a single threaded application, as the whole thread will stop responding until the function returns. waitForRead() is most useful when there is no event loop available. The general approach is to create a QSocketNotifier, passing the socket descriptor returned by socketDescriptor() to its constructor.
[override virtual]
bool QNativeSocketEngine::waitForWrite(int msecs = 30000, bool *timedOut = nullptr)
Waits for msecs milliseconds or until the socket is ready for writing. If timedOut is not nullptr
and msecs milliseconds have passed, the value of timedOut is set to true.
Returns true
if data is available for writing; otherwise returns false.
This is a blocking function call; its use is disadvised in a single threaded application, as the whole thread will stop responding until the function returns. waitForWrite() is most useful when there is no event loop available. The general approach is to create a QSocketNotifier, passing the socket descriptor returned by socketDescriptor() to its constructor.
[override virtual]
qint64 QNativeSocketEngine::write(const char *data, qint64 size)
Writes a block of size bytes from data to the socket. Returns the number of bytes written, or -1 if an error occurred.
Passing zero as the size parameter on a connected UDP socket will send an empty datagram. For other socket types results are unspecified.
[override virtual]
qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 size, const QIpPacketHeader &header)
Writes a datagram of size size bytes to the socket from data to the destination contained in header, and returns the number of bytes written, or -1 if an error occurred. If header contains other settings like hop limit or source address, this function will try to pass them to the operating system too, but will not indicate an error if it could not pass them.
Only one datagram is sent, and if there is too much data to fit into a single datagram, the operation will fail and error() will return QAbstractSocket::DatagramTooLargeError. Operating systems impose an upper limit to the size of a datagram, but this size is different on almost all platforms. Sending large datagrams is in general disadvised, as even if they are sent successfully, they are likely to be fragmented before arriving at their destination.
Experience has shown that it is in general safe to send IPv4 datagrams no larger than 512 bytes or IPv6 datagrams no larger than 1280 (the minimum MTU).
See also readDatagram().