Jump to content


A few "socket" questions


  • You cannot reply to this topic
18 replies to this topic

#1 Goz

    Senior Member

  • Members
  • PipPipPipPip
  • 574 posts

Posted 18 November 2008 - 11:13 PM

Ok so i've just started dabbling in network programming for the first time.

I've got some basic stuff up and i'm using winsock to pass strings between 2 threads. Now I have a few questions about how it all works that I haven't managed to glean from the docs.

Do note that my "server" and "client" are 2 seperate threads on the same machine. I only have one machine I can play with at the moment. This may impact things.

My "server" is currently set up to bind a UDP socket to my specified port (12345 for this testing). I then sit and wait for a message to arrive using recvfrom.

My "client" then sends a message to the ip and port specified using send to. No sockets are bound.

This message is received by the server without any problems and I take note of the ip address and port that the message came from. All well and good.

I then use the recorded ip and port to "sendto" a message back from the server to the client. All well and good at this point. What confuses me, however, is that I can then recvfrom at the client end. I haven't "bind"ed the client socket to a given port so ...

1) How does it know it can receive data on that port?
2) Does sendTo make the relevant connections internally?
3)If I have 5 clients sending 1 packet of data to the same port on my server will they come through one by one in 5 seperate recvfrom calls?
4) How does using overlapped sockets affect (3) if at all?
5) When using overlapped sockets what is the best way to check if there is data waiting (ie using WSAPoll or just calling WSARecvFrom)?
6) How different are windows and unix/linux (and MacOS for that matter) in the way they handle asynchronous sockets?

I would also appreciate being told of any stupid mistakes I am making!

Cheers :)

#2 Reedbeta

    DevMaster Staff

  • Administrators
  • 4968 posts
  • LocationBellevue, WA

Posted 19 November 2008 - 12:07 AM

1.2. I believe when you make an outgoing connection, the OS automatically assigns an unused port to receive replies, or something like that.
3. Yes, recvfrom will get one packet at a time for the UDP case.

As for the others, don't know...never got into socket-level networking that much myself.
reedbeta.com - developer blog, OpenGL demos, and other projects

#3 imerso

    Senior Member

  • Members
  • PipPipPipPip
  • 428 posts
  • LocationBrasil

Posted 19 November 2008 - 01:18 AM

My answers may be inaccurate at some points, because I am trying to answer from memory, but they will be close to correct (at least I hope so):

1) Check if ioctlsocket(udpSock, FIONREAD, &data) == SOCKET_ERROR, if not, then if data>0 there is data to read -- just use recvfrom() to read;

2) Yes. It will put data into the remote part, so the remote can read it, but UDP, differently from TCP does not keep a connection with the other part;

3) Yes. And even from one single client, different packets may (and will frequently) come out of order;

4) If you keep a record for each different remote ip that is sending data to you, there is no problem with that;

5) You may just use ioctlsocket();

6) They are very similar in funcionality, almost the same, but there are different includes and Win32 requires winsocket initialization/linking.

#4 TheNut

    Senior Member

  • Moderators
  • 1469 posts
  • LocationThornhill, ON

Posted 19 November 2008 - 04:03 AM

Just a tip with UDP connections. As a client, you can still use the connect() function to establish the UDP socket. You can now use the send() and recv() functions normally without the need for sendto() or recvfrom(). You may find that easier to work with rather than doing lookups on the ip address, which can be slow.

1) & 2) have been answered correctly for you. Although I'll add you can still bind a port manually if you want, especially if someone is behind a firewall. More so if you're a server (but I'm sure you came across that already ;)

3) To understand this better, lookup the naggle algorithm. This is used only on TCP streams to maximize bandwidth efficiency. UDP is a real-time protocol so the message you send is dispatched immediately.

4) Answered above. It's common for servers to adopt a hash table using the network ip address (unsigned int) as the index to store client information in for quick retrieval and processing.

5) Truthfully you should never really be checking if data in a socket is ready, just always read data. When something's coming in, you'll know soon enough ;)

6) As said above, but I'll throw you a tip. Both Windows and *nix treat the socket as an int32. Basically to store the address location of it. However, it's common to see Windows developers use the typedef SOCKET. *nix doesn't use that typedef. My advice, avoid that. Treat your socket reference as an int and your code will be compiled on both platforms easily. Also isolate all your WSA calls in a separate class and compile it only on Win32 platforms, just to initialize the socket library. Other than initializing sockets and getting human readable socket errors, discard any use of WSA afterwards.
http://www.nutty.ca - Being a nut has its advantages.

#5 Anddos

    Valued Member

  • Members
  • PipPipPip
  • 161 posts

Posted 19 November 2008 - 10:50 AM

how would you send and recieve vector3 over a socket , would you have to cast it to char*?

#6 imerso

    Senior Member

  • Members
  • PipPipPipPip
  • 428 posts
  • LocationBrasil

Posted 19 November 2008 - 11:34 AM

cast to void*

#7 Anddos

    Valued Member

  • Members
  • PipPipPip
  • 161 posts

Posted 19 November 2008 - 01:51 PM

example?
i was thinking
send(sock,(char*)&vect,sizeof(vect),0);
then also recieve like that

#8 imerso

    Senior Member

  • Members
  • PipPipPipPip
  • 428 posts
  • LocationBrasil

Posted 19 November 2008 - 02:19 PM

Something like:

typedef struct _PACKET
{
    Vec3 position;
    Vec3 orientation;
} mypacket;

...

mypacket pk;
pk.position = ...;
pk.orientation = ...;
send(sock, (void*)&pk, sizeof(pk), 0);

Then, the other part receive the bytes directly over the same _PACKET structure.

#9 Goz

    Senior Member

  • Members
  • PipPipPipPip
  • 574 posts

Posted 19 November 2008 - 03:24 PM

TheNut said:

Other than initializing sockets and getting human readable socket errors, discard any use of WSA afterwards.

Can you do non-blocking sockets without the WSA stuff then?

#10 Kenneth Gorking

    Senior Member

  • Members
  • PipPipPipPip
  • 911 posts

Posted 19 November 2008 - 05:33 PM

Yes, with ioctlsocket.
"Stupid bug! You go squish now!!" - Homer Simpson

#11 Goz

    Senior Member

  • Members
  • PipPipPipPip
  • 574 posts

Posted 19 November 2008 - 07:58 PM

Kenneth Gorking said:

Yes, with ioctlsocket.

LOL ... i read that page so many times and totally missed that! :)

#12 Anddos

    Valued Member

  • Members
  • PipPipPip
  • 161 posts

Posted 20 November 2008 - 10:55 AM

vrnunes said:

Something like:


typedef struct _PACKET

{

    Vec3 position;

    Vec3 orientation;

} mypacket;


...


mypacket pk;

pk.position = ...;

pk.orientation = ...;

send(sock, (void*)&pk, sizeof(pk), 0);


Then, the other part receive the bytes directly over the same _PACKET structure.

rror C2664: 'send' : cannot convert parameter 2 from 'void *' to 'const char *'
Conversion from 'void*' to pointer to non-'void' requires an explicit cast

but this compiles

send(sock, (char*)&pk, sizeof(pk), 0);

#13 imerso

    Senior Member

  • Members
  • PipPipPipPip
  • 428 posts
  • LocationBrasil

Posted 20 November 2008 - 12:14 PM

Hmmm Yes, I checked that on my own net code and I was indeed using a byte buffer pointing to that structure, before doing the cast to void*. :whistle:

Nice.

#14 Anddos

    Valued Member

  • Members
  • PipPipPip
  • 161 posts

Posted 20 November 2008 - 01:13 PM

dammit i cant seem to make a server accept 2 connections
if ((AcceptSocket = accept(sock, NULL, NULL)) != INVALID_SOCKET)
<Mrbooney> if ((AcceptSocket2 = accept(sock, NULL, NULL)) != INVALID_SOCKET)
can anyone help
if (listen(sock, 2))
2 connections..

#15 Goz

    Senior Member

  • Members
  • PipPipPipPip
  • 574 posts

Posted 25 November 2008 - 11:18 PM

TheNut said:

Just a tip with UDP connections. As a client, you can still use the connect() function to establish the UDP socket. You can now use the send() and recv() functions normally without the need for sendto() or recvfrom(). You may find that easier to work with rather than doing lookups on the ip address, which can be slow.

Going back to this, So I DO need to do recvFrom and sendTo on the server end?

I ask because I'm just slightly confused. Suppose you have 2 machines behind a NAT firewall. Both are connected to the same server. How does the server know which machine is which? I ask because surely both will show up with the same IP address and port? Or does the NAT router handle all this transparently?

A decent explanation of how NAT works would be handy :)

#16 TheNut

    Senior Member

  • Moderators
  • 1469 posts
  • LocationThornhill, ON

Posted 26 November 2008 - 12:08 AM

Quote

Going back to this, So I DO need to do recvFrom and sendTo on the server end?
Yes. You can't do it on the server end because you've already bound to a specific port to listen for UDP packets. If you attempt to create a "connection" (not really a connection in UDP sense, but socket initialization) back to the client using the same local port, you'll get a port in use error.

Quote

decent explanation of how NAT works would be handy
In a most simplistic explanation, it simply takes the sender's address and modifies it to the NAT's own local address before sending the packet out. It knows who to return it to because a new port will be assigned on the NAT's machine when the packet goes out. This is why some games work behind a NAT (ie: playing Counter Strike online at a LAN party) because multiple connections are made from the NAT machine to the game server, but each one on a different local port (not to be confused with the remote port, which is the port the game server is hosting on).

Also, it's not possible to have two identical IPs behind a NAT, or behind any routing device for that matter. Each router has a lookup table which stores your information when it first discovers you on the network (ie: you sent something). If someone with the same IP comes by, the router will (depending on its quality and security level) update its table and point to the new sender.
http://www.nutty.ca - Being a nut has its advantages.

#17 Goz

    Senior Member

  • Members
  • PipPipPipPip
  • 574 posts

Posted 26 November 2008 - 07:26 AM

TheNut said:

Yes. You can't do it on the server end because you've already bound to a specific port to listen for UDP packets. If you attempt to create a "connection" (not really a connection in UDP sense, but socket initialization) back to the client using the same local port, you'll get a port in use error.

Cool :)


Quote

In a most simplistic explanation, it simply takes the sender's address and modifies it to the NAT's own local address before sending the packet out. It knows who to return it to because a new port will be assigned on the NAT's machine when the packet goes out. This is why some games work behind a NAT (ie: playing Counter Strike online at a LAN party) because multiple connections are made from the NAT machine to the game server, but each one on a different local port (not to be confused with the remote port, which is the port the game server is hosting on).

Also, it's not possible to have two identical IPs behind a NAT, or behind any routing device for that matter. Each router has a lookup table which stores your information when it first discovers you on the network (ie: you sent something). If someone with the same IP comes by, the router will (depending on its quality and security level) update its table and point to the new sender.

OK so if i understand you correctly then each machine behind the NAT will open a connection to the server on a different port? or Does the NAT re-map this internally?

If the former, does winsock fail when you "connect" on a certain port? How do you know that another machine is not already using the port you want to use?

Cheers for the help TheNut :)

#18 TheNut

    Senior Member

  • Moderators
  • 1469 posts
  • LocationThornhill, ON

Posted 26 November 2008 - 11:46 AM

There's two mappings. The computer behind the NAT will find an available local port that the NAT server will communicate back on. It's purely random. When the NAT has to dispatch that computer's request out into the Internet (or some other network), it will also find a random unused local port the remote server needs to communicate it with. The NAT handles all the translations.

example:

Ports             ------> 80 ------>   ------> 80 ------>

Internal Network                    NAT                  Web Server

                  <------ 32572 ---    <------ 52478 ----


You send a request out to some web server. The NAT receives your IP address and port. It will record that to some lookup table. It then modifies those values to match with its own network, so that it will get the response. It knows what ports it has available, so it will never collide with anyone else. It then resumes to send out your initial request. Upon return, it realizes the port number returned in the message belongs to you (via the lookup table and no one else has this port because it was created and assigned by the NAT), and so replaces the destination IP and port with your information. Within a couple milliseconds, you will get the message.
http://www.nutty.ca - Being a nut has its advantages.

#19 Goz

    Senior Member

  • Members
  • PipPipPipPip
  • 574 posts

Posted 26 November 2008 - 03:27 PM

Ok thats pretty cool. NAT is evidently a hell of a lot more intelligently put together than I gave it credit for :D





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users