I have these 2 lines of code.
I need a socket that just receives data
The first method is working, and I receive date (from the ip/port in the second method)
The second method is always returning false.
I don't understand the difference and can't find the problem.
Any one have any idea how to resolve this or what I'm doing wrong?
udpSocket = new QUdpSocket();
bool result = udpSocket->bind(QHostAddress::Any, 7755);
QHostAddress address("the ip")
udpSocket = new QUdpSocket();
bool result = udpSocket->bind(address , 7755);
In first method, when you bind the socket bind(QHostAddress::Any, 7755) it will listen on all interfaces on your system; thus it will bind successfully knowing that at least one interface is up.
In the second method, when you set the IP Address with QHostAddress address("the ip") you need to make sure that an interface is up with that IP address at your system (use ipconfig on Win / ifconfig on Linux).
Now the constructor will automatically detect from the string passed ("ip address") whether its IPv4 or IPv6.
If you are not specifying a type, then you can construct the address as Any and bind your socket to it:
QString string("192.168.1.1");
QHostAddress address(QHostAddress::Any);
address.setAddress(string);
udpSocket = new QUdpSocket();
bool result = udpSocket->bind(address , 7755);
Related
I tried to bind my socket to some random address 10.1.1.1:12001, and got QAbstractSocket::SocketAddressNotAvailableError.
Than i wrote a simple code:
for (int i = 0; i < 256; i++) {
QHostAddress address0(QString::number(i) + ".0.0.1");
quint16 port = 12101;
QUdpSocket* m_socket = new QUdpSocket();
if (m_socket->bind(address0, port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint)) {
qDebug() << i;
}
}
Only to learn that IP must start with 127 or 224-239. So it must be Class D address.. But I just didn't find anything in the qt documentation.
Is it a normal behaviour? Is there a possibility to use a global net IP for binding? Or at least use 192.168.x.x as IP of another computer in LAN?
You are not allowed to bind the socket to an arbitrary network IP address. You can only do it with an IP address of one of your network devices or some special IP addresses like 0.0.0.0. By default you always have the 127.0.0.1 but surely you have another network address in your computer.
By the other way if you want to write/read some data over an UDP Socket It's not necessary to bind it to a network address, you can use writeDatagram() or readDatagram() methods of the QUdpSocket class
How is it possible to get next open tcp port on windows
I've searched the web and i came across TcpPortsGatherer written in Qt...
the only problem is that its not available in my current Qt version or it should be used as a plugin
so I'm looking for a way to use TcpPortsGatherer Class
or just use native windows libraries if any is available
Update :
I've Used Sebastian's approach like below to bind the found port to an external binary that I run but it always assign the port 1025 to the executable , how can i fix this ?
QTcpSocket *socket = new QTcpSocket();
qint16 port = 1025;
while(!socket->bind(port, QAbstractSocket::DontShareAddress))
port++;
socket->close();
socket->deleteLater();
Just specify port zero and bind. The system will give you the next available port. No loop required.
You could just try using QTcpSocket::bind(). It will return a bool(true) if port open was successfull.
QTcpSocket *socket = new QTcpSocket();
qint16 port = 1025;
while(!socket->bind(port, QAbstractSocket::DontShareAddress))
{
port++;
}
socket is now bound to port.
I am trying to send data to a computer with specific ip address on Qt.
If I use Broadcast everything is fine. But when I want to send data to a specific address it does not work. Here is what I have in the transmitter:
udpSocket = new QUdpSocket(this);
QHostAddress myAddress = QHostAddress("192.160.0.1");
udpSocket->writeDatagram((char*)myChar, len, myAddress, 45454);
and at the receiver I have:
udpSocket->bind(45454, QUdpSocket::ShareAddress);
Am I doing something wrong?
Thanks for the help.
After reviewing everything carefully it turned out that I miss typed the receiver ip address. Everything in the above setup is correct and is working.
I need to get the IP address of a connection to see if it has already connected previously (checking against a list of ips, if it has connected previously but isnt connected anymore, it will say offline). (using nonblocking sockets)
How can I get the IP without first accepting it.
///
case FD_ACCEPT:
int W;
for(W = 0;W <= ListView_GetItemCount(GetDlgItem(HwND,IDC_IPLIST));W++){
So then im just gonna check the IP against the list view to see if it had connected before. If it has, I want to use the same socket number it was using last time.
This is how I'm accepting connections right now
case FD_ACCEPT:
while(Client[F] != NULL)
{
F++;
}
Client[F]=accept(wParam,(LPSOCKADDR)&ServAdr,&AdrLen);
break;
so to break it down...
I want to check incoming connections against an IP list of previous connections. This list will have the IP and whether its online/offline (connected/not connected). If it has connected before I want it to show Online when I accept the new connection, and use the same socket number it used last time instead of using a new one all together. If it hasn't I want it to be added to the list. (the list will have the socket number)
If this doesnt make much sense I'll try and clarify a bit more.
What you are asking for cannot be done with accept(). You do not have access to a connection's information until after it has been accepted and a new SOCKET handle allocated. To get the connection info pre-acceptance, you have to use the callback functionality of WSAAccept() instead.
Either way, there is no way to reuse an existing SOCKET handle for a new connection. Each accepted connection must have its own unique SOCKET handle. You can certainly associate the new connection from a previously-seen IP with an existing slot in your ListView, though.
If by socket number you mean the number returned by accept(), you can't rely on it's value at all. I mean, if the remote host disconnects and connects again the value returned by accept() will most probably be different. It does not make sense to rely on this number.
If by socket number you mean the position in your array, you can assign the value returned by accept() to temporary variable:
SOCKET tmpSock;
sockaddr_in tmpAddr;
int namelen;
typedef struct { /*...*/ } TClient;
TClient Client[MAX_CLIENTS];
/*...*/
tmpSock = accept(/*...*/);
namelen = sizeof(tmpAddr);
getpeername(tmpSock, (sockaddr*)&tmpAddr,&namelen);
/*...*/
//looking for tmpAddr.sin_addr in your list and calculating
//the list position - F
/*...*/
Client[F].Socket = tmpSock;
Client[F].IsConnected = true;
Client[F].Address = tmpAddr.sin_addr;
Have in mind that after the listen() call the OS kernel will accept all incoming connection to the port/local IP set by you. It means that the connect() of remote host will return successfully whether you call accept() or not (provided you have space in listen queue). Calling accept() will only allow you to interact with the socket. It will not change the connection state seen by the remote host.
I'm not sure the is possible nor an efficient specification to achieve what you want. I would either:
Accept any connection and then check the IP address, disconnecting connections which are not in the list
(This probably isn't suitable for you) Configure an upstream firewall, such that only allowed IP addresses are allowed through.
If you bind to a wildcard address (INADDR_ANY), then the IP address used for communication isn't determined until a connection comes in (it will be one from the interface the packets are passing through). The same listening socket can result in accepted connections on more than one IP address.
If you bind to a specific address, then you already know the address you bound to.
I have a problem with a c++ socket.
I'm using CAsyncSocket from MFC that i want to join a multicast group.
Also I need to have multiple listener on this group and here is where i get in trouble.
I found some examples on the web but it doesn't seems to work.
Here is my code:
//create socket on port 17233
BOOL bRet = Create(17233,SOCK_DGRAM, FD_READ);
//set reuse socket option
BOOL bMultipleApps = TRUE;
bRet = SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET);
//join multicast group
ip_mreq m_mrMReq; // Contains IP and interface of the host group
m_mrMReq.imr_multiaddr.s_addr = inet_addr((LPCSTR)"224.30.0.1"); /* group addr */
m_mrMReq.imr_interface.s_addr = htons(INADDR_ANY); /* use default */
int uRes =setsockopt(m_hSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char FAR *)&m_mrMReq, sizeof(m_mrMReq));
There are no errors when i run this.
But when i try to run another instance of the app it fails to create a new socket on that port because the port is in use.
I have done this in C# and it worked fine like this:
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port);
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
s.Bind(ipep);
IPAddress ip = IPAddress.Parse(mcastGroup);
s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ip, IPAddress.Any));
s.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.MulticastTimeToLive, int.Parse("1"));
So if any body sees a problem with my code or have some tips i will gladly appreciated.
EDIT 1:
Is CAsyncSocket a TCP socket?
EDIT 2:
After reading Can two applications listen to the same port?
I think i made a confusion. I need a Multicast UDP port that can be access by multiple application using SO_REUSEADDR
Edit for Clarification:
BOOL bRet = Create(17233,SOCK_DGRAM, FD_READ)
Creates an UDP socket and bind's to to port 17223.
For SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET); to work you need to set it before binding as #Hasturkun said.
The final working code looks like this:
BOOL bRet = Socket(SOCK_DGRAM, FD_READ);
if(bRet != TRUE)
{
UINT uErr = GetLastError();
std::cout<<"Error:"<<uErr<<std::endl;
return FALSE;
}else{
std::cout<<"Create sock: OK"<<std::endl;
}
//add reuse
BOOL bMultipleApps = TRUE; /* allow reuse of local port if needed */
SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET);
//bind
bRet = Bind(17233, NULL);
if(bRet != TRUE)
{
UINT uErr = GetLastError();
std::cout<<"Error(BIND):"<<uErr<<std::endl;
}else{
std::cout<<"BIND sock: OK"<<std::endl;
}
Thanks,
Gabriel
;
You should be able to separate the creation of the socket from the binding, create the socket using Socket, eg.
BOOL bRet = Socket(SOCK_DGRAM, FD_READ);
Then bind it with Bind after setting the sockopt
BOOL bMultipleApps = TRUE;
bRet = SetSockOpt(SO_REUSEADDR, (void*)&bMultipleApps, sizeof(BOOL), SOL_SOCKET);
bRet = Bind(17233, NULL);
This happens, i guess, because you are binding a client socket to a specific port and address. Maybe on its constructor:
BOOL bRet = Create(17233,SOCK_DGRAM, FD_READ);
You should not binding a client socket to an address. Let windows manage this for you. You should have a option to not create the socket passing a specific port, or if you do not, you should create the socket using another port.
Also, the BOOL bMultipleApps = TRUE; option does not work the way you think it does. It sets a linger option in the socket, but once created and listening, the socket (i mean the socket port) cannot be used in other applications no mather what you do.
Check this out: so-linger-and-closing-socketswinsock
EDIT:
I also dont know that the value of port in your c# code:
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port);
Are you sure that port does not get a different value every time you run the app?
As I said, try to create the socket in a different port to see what happens. Google for so_linger to know what it means.
EDIT 2:
Take a look at: Can two application listen to the same port?
EDIT 3:
Maybe your c# code:
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, port);
is binding the address to a different NIC. Do you have 2 nics at the same computer? If you do, you can bind the same port in both of them.
EDIT 4:
Example of using UDP sockets: Sending & Receiving UDP Datagrams with MFC's CAsyncSocket
If boost is an option for you, consider using Asio for this. It is very straight-forward and this example shows a simple multicast receiver.
The important part for multiple listeners is:
socket_.set_option(boost::asio::ip::udp::socket::reuse_address(true));
If you're unclear what your application is doing, just run netstat and you'll see e.g. the sockets and how they are bound (IP, port and protocol):
netstat -an
...and look for the port you're interested in. If you run multiple applications listening to the same port you should see multiple entries for the same port with UDP as protocol.