Sign in to follow this  

sendin to specific client with udp

This topic is 4247 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I want to reply to a client after I receive a packet from them but what I'm trying isn't working. I have them both set up on the same port. Right now I have the client send a packet and I get it with recvfrom. and store who it's from in a sockaddr_in structure. Then I set the original sin_addr I set the server connection up with to the sin_addr from the from structure but what's happening is that the server is just sending the packet to itself since both the client and server are running on the same machine. Anyone know how to fix it so my client gets the packets my server sends?

Share this post


Link to post
Share on other sites

It's been a long time I worked with networking stuff. As far as I remember, you shouldn't set up the client on any specific port. Let the system decide the client port.

It is possible to have the client and the server on the same machine.

Share this post


Link to post
Share on other sites
if I don't set the port on the client the packet never makes it to my server.

Share this post


Link to post
Share on other sites
The information given to you by recvfrom() should include a client's address and port. If you send back to the same place you got it from that should work.

Share this post


Link to post
Share on other sites
Quote:
Original post by etsuja
if I don't set the port on the client the packet never makes it to my server.


This sounds like an overzealous firewall. You need to ensure the port is open and forwarding to the server.

It's a REALLY good idea to let the system assign UDP port for outgoing connections. This allows you to run multiple clients on the same machine (useful for debugging) without getting into complications as to which send came from which client.

Read up the man pages for sendto(...) and recvfrom(...). What you get from recvfrom(...) on your server is what you should sendto(...) from your server. On your client recvfrom(...) should give you the IP and port of your server, which should also be the only thing you ever send to, unless you're building a peer-to-peer system. You should store these addresses on a per-client basis (identifying client primarily by IP AND PORT), not anywhere else.



Share this post


Link to post
Share on other sites
If my server is bound to a specific port and my client doesn't specify which port to send data to how will the server get the data sent to some random port specified by the client?

Share this post


Link to post
Share on other sites
I think we're saying it's a bad idea to use bind() on a UDP socket on a client machine. Clearly, you have to use it on the server.
bind() tells the machine what port it should listen on (and send FROM).
sendto() tells the machine what remote port it should send to.
You can also use connect() to say what remote port to send to, but then you can't re-use that socket for other ports later.

Share this post


Link to post
Share on other sites
I wasn't binding on the client... Do I need to in order for it to receive anything? And if I don't how do I receive anything with the client?

Share this post


Link to post
Share on other sites
No, you don't need to bind on the client.

When you create a UDP socket it has a port assigned by the system, if you use that socket to send (sendto) the port it sent on is held open, and you can receive on it. The port number doesn't change from send to send.

So all your server has to do is store the IPs and ports of the clients that connect to it to tell them apart. Don't rely on a certain port source for authentication.

Share this post


Link to post
Share on other sites
Quote:
Original post by _winterdyne_So all your server has to do is store the IPs and ports of the clients that connect to it to tell them apart. Don't rely on a certain port source for authentication.

Apparently NAT can sometimes change the port used to forward packets from a client. It is a good idea to also include some information in the packet which you can use to relate the incoming packets to an known client.

Talking about binding/not binding for UDP, I have a couple of questions too:
Is it possible to know which port the socket got assigned to if you leave it up to the system?
For TCP, when two processes bind to the same port, the second one will fail because the port is already in use. I haven't seen that happen for UDP - is is supposed to be that way, or can I set something to make sure the second bind will fail (which is what I want) ?

Share this post


Link to post
Share on other sites
ok, I tried sending to the client with the address and port I get from it but it still never receives anything.

Share this post


Link to post
Share on other sites
To know the port assigned by the system, use ::getsockname().

If you use sendto() to reply back to the address you get from recvfrom(), you either have a bug in your code, or a bad firewall. You can use something like Ethereal on the client and server machines to sniff all UDP traffic, and see whether anything actually leaves the server machine when it attempts to reply.

Share this post


Link to post
Share on other sites
I tried giving my server and client full access with my firewall and tried shutting it off but it still didn't work.... here's what I'm doing.

here's my servers send and receive function

void SendRcv()
{

RcvTest = 0;
RcvTest = recvfrom(UDPSocket, RcvBuff, MAX_BUFFER, 0, (struct sockaddr *)&from, &len);

InBuffer = RcvBuff;

if(atoi(&InBuffer[0]) == PCKT_LOGIN)
{
AddString(TEXT("COOL"));

string ALoginName;
string APassword;

ACNTSTRUCT* ThisAccount = FirstAccount;
string ThisAccountName;
string ThisAccountPassword;

while(ThisAccount != NULL)
{
string::size_type Pos = InBuffer.find(ThisAccount->AcntLoginName,0);

if(Pos != string::npos)
{
string::size_type Pos = InBuffer.find(ThisAccount->AcntPassword,0);

if(Pos != string::npos)
{
service.sin_addr = from.sin_addr;
service.sin_port = from.sin_port;

if(ThisAccount->AcntLoggedIn == TRUE)
{
OutBuffer = "You already Logged in";
sendto(UDPSocket, OutBuffer.c_str(), sizeof(OutBuffer), 0, (SOCKADDR *)&service, sizeof(SOCKADDR));
}
else
{
OutBuffer = "You Logged in now";
sendto(UDPSocket, OutBuffer.c_str(), sizeof(OutBuffer), 0, (SOCKADDR *)&service, sizeof(SOCKADDR));
ThisAccount->AcntLoggedIn = TRUE;
}
}

}
ThisAccount = ThisAccount->Next;
}


}
}




and here's my test clients. Does rcvfrom block the rest of the app from running? Its runningon a seperate thread on my server.

test = sendto(UDPSocket, buffer, sizeof(buffer), 0, (SOCKADDR *)&service, sizeof(SOCKADDR));
if(test == SOCKET_ERROR)
{
printf("no data sent");
}

if((test == SOCKET_ERROR) || (test < 0))
{
printf("FUCK!!");
}
else
{
printf("%s sent",buffer);
}

int testie = 0;


testie = recvfrom(UDPSocket, InBuffer, 256, 0, NULL, &len);

if(testie > 0)
{
printf("%s", InBuffer);
break;
}


Share this post


Link to post
Share on other sites
I can't begin to describe how horrible [I think] that code is or for how many reasons. Do not, in the name of all that's holy, expect that stuff to work properly, especially when you need to send more complex messages.

Firstly, you're assuming you'll receive a string. Strings are zero terminated. Buffers are not. Assuming the data you've received is the data you want is wrong. And evil. And wrong.

When doing network coding you absolutely definitely MUST MUST MUST check the data you receive. Not doing so WILL end up with you having buffer overruns, heap violations and all sorts of hell as your app crashes in unrelated threads (a painful experience).

Why the atoi? I really don't follow what you're trying to do here. There's no packet format there - which is going to make debugging and packet-dumping (essential techniques) impossible. Here [LINK] is a thread going into UDP packet format - you need to look at this, and implement something similar so you know how much data you need to expect from a given buffer, and if the received buffer is complete, aggregated, or corrupt - UDP can and eventually is going to send you packets out of order, drop them, and generally be the unreliable beast it is. Also the help in debugging is invaluable - do it now, before it's too late. Edit: to those in the TCP camp, if nagling is active on the socket, it will aggregate small packets into a single transmission unit - each tick you might receive various chunks of packets (including a partial (truncated) packet).

You're using C++. Make use of it - wrapping sockets into classes is the only way to go - encapsulation helps you keep bugs contained.

If you want to set your socket to non-blocking, this is done with ioctl, something like:
[source lang=cpp]
bool WSSocket::setBlocking(bool bBlocking)
{
if (!m_bReady)
{
m_pLog->log("WSSocket %x trying to set blocking mode before ready!\n",this);
return false; // Socket must be created to change mode
}

unsigned long val;

#ifdef WSCORE_LINUX

if (bBlocking)
{
// We want to be blocking
val = 0;
if (!m_bBlocking) // We WANT to be blocking but we're NOT
{
if (ioctl(m_sock, FIONBIO, &val)<0)
return false;
m_bBlocking = true;
return true;
}
return true; // We blocking and we want to be
}
else
{
// We don't want to be blocking
val = 1;
if (m_bBlocking) // We DON'T want to be blocking but we ARE
{
if (ioctl(m_sock, FIONBIO, &val)<0)
return false;
m_bBlocking = false;
return true;
}
return true; // We not blocking and we don't want to be
}

#endif


#ifdef WSCORE_WIN32 // ioctl only applies to sockets under linux - hence ioctlsocket.

if (bBlocking)
{
// We want to be blocking
val = 0;
if (!m_bBlocking) // We WANT to be blocking but we're NOT
{
if (ioctlsocket(m_sock,FIONBIO,&val)<0)
return false;
m_bBlocking = true;
return true;
}
return true; // We blocking and we want to be
}
else
{
// We don't want to be blocking
val = 1;
if (m_bBlocking) // We DON'T want to be blocking but we ARE
{
if (ioctlsocket(m_sock,FIONBIO,&val)<0)
return false;
m_bBlocking = false;
return true;
}
return true; // We are not blocking and we don't want to be
}

#endif
};





Edit: Take note that the winsock equivalent of ioctl is ioctlsocket, since it only applies to berkely sockets under windows.

I also just noticed you're apparently sending the login name with every packet? Don't do this - recvfrom can identify the client after the first receive from it (perhaps you may want an integer id (SERVER ASSIGNED) in messages, but not necessary). Until you can bounce simple messages back and forth between 2 machines don't worry about a login system. When you can bounce messages between 2 machines extend it to 3 then 4. THEN do a login system so you can identify each client. Then implement 'tell's and so on, and you're getting there.

[Edited by - _winterdyne_ on June 1, 2006 7:18:27 AM]

Share this post


Link to post
Share on other sites
ok, I'm just starting networking so excuse me if I don't know every little detail and the best coding for it. but this isn't the final code anyways I was just using this for testing. I'm also not sending the login name with every packet. the atoi was to check the first character in the packet to see what kind of packet it was and at the moment I was jest using my client to send strings. Anyways all I want to know is why my client isn't receiving anything or if the if statement just isn't running with the code provided.

Share this post


Link to post
Share on other sites
Well I got it working. All I did was make a from structure for the client and put it in the from parameter of recvfrom and it works. I didn't think you absolutely needed that parameter but I guess you do.

Share this post


Link to post
Share on other sites

This topic is 4247 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this