转自http://www.cnblogs.com/F-32/archive/2012/03/23/2414204.html
Author F32 (feng32@163.com)
The code is released under the terms of GNU Lesser General Public License version 2.1
Here's the code.
#ifndef Q_BOUND_TCP_SOCKET_H
#define Q_BOUND_TCP_SOCKET_H
#include <QTcpSocket>
/**
* \brief The QBoundTcpSocket class adds binding support
* to tcp client sockets.
*
* In Qt 4, it's impossible to bind a tcp client socket to
* a specific port or ip address.
*
* This feature has been added to Qt 5, however with version 4,
* it's still possible to do binding while getting convenience from
* the Qt framework.
*
* Note:
*
* Due to usage of native api, the class currently not supports
* platforms other than Linux. If you are familiar with
* native programming interfaces like winsock, porting the code
* to other operations systems may be just a piece of cake.
*
* A QBoundTcpSocket object will bind and connect to the server
* at the same time, because the only way to work around is to
* create a socket, bind, connect to server with native API from the
* OS, and then pass the socket to QTcpSocket::setSocketDescriptor
* with a connected state.
*/
class QBoundTcpSocket : public QTcpSocket
{
public:
/**
* \brief Bind the socket and then connect to server
*
* Note:
*
* Before calling, the socket must be in the unconnected state,
* otherwise a value of false is returned.
*
* Typical usage:
* \code
* QBoundTcpSocket socket;
* if (socket.bindAndConnect("192.168.1.10", 0, "10.0.0.1", 80))
* {
* // Now bound and connected
* }
* else
* {
* qDebug() << "An error occurred in QBoundTcpSocket::bindAndConnect";
* }
* \endcode
*
* \param localAddr Local IP address (e.g., "10.0.0.10").
* A value of "0.0.0.0" indicates that
* the default ip address will be used.
* \param localPort Local port (e.g., 12345).
* A value of 0 indicates that any port is acceptable.
* \param serverAddr IP address of the server (e.g., "10.0.0.1")
* \param serverPort Port of the server (e.g., 80)
*
* \return The return value is true when both binding and connecting
* are successful, and false otherwise.
*/
bool bindAndConnect(const QString &localAddr, quint16 localPort,
const QString &serverAddr, quint16 serverPort);
};
#endif /* Q_BOUND_TCP_SOCKET_H */
#include "QBoundTcpSocket.h"
#ifdef Q_OS_LINUX
#include <arpa/inet.h>
#endif
bool QBoundTcpSocket::bindAndConnect(const QString &localAddr, quint16 localPort,
const QString &serverAddr, quint16 serverPort)
{
#ifdef Q_OS_LINUX
int sockfd;
int result;
struct sockaddr_in localSockAddr;
struct sockaddr_in serverSockAddr;
bzero(&localSockAddr, sizeof(localSockAddr));
bzero(&serverSockAddr, sizeof(serverSockAddr));
// create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if( sockfd == -1 )
{
qDebug() << "QBoundTcpSocket: Cannot create socket";
return false;
}
// bind
localSockAddr.sin_family = AF_INET;
localSockAddr.sin_port = htons(localPort);
localSockAddr.sin_addr.s_addr = inet_addr(localAddr.toLocal8Bit().data());
result = bind(sockfd, (struct sockaddr *)&localSockAddr, sizeof(localSockAddr));
if( result == -1 )
{
qDebug() << "QBoundTcpSocket: Cannot bind socket";
return false;
}
// connect
serverSockAddr.sin_family = AF_INET;
serverSockAddr.sin_port = htons(serverPort);
serverSockAddr.sin_addr.s_addr = inet_addr(serverAddr.toLocal8Bit().data());
result = ::connect(sockfd, (struct sockaddr *)&serverSockAddr, sizeof(serverSockAddr));
if( result == -1 )
{
qDebug() << "QBoundTcpSocket: Cannot connect to server";
return false;
}
// set socket descriptor
if( !setSocketDescriptor(sockfd, QAbstractSocket::ConnectedState))
{
qDebug() << "QBoundTcpSocket: Cannot set socket descriptor";
return false;
}
return true;
#else
qDebug() << "QBoundTcpSocket for Windows/Mac OS is not implemented yet";
return false;
#endif
}