Archived

This topic is now archived and is closed to further replies.

TCP/IP Ports

This topic is 5952 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

How many connections can you have through a single TCP/IP port? Does the port have a bandwidth. I''m using the WinSock API at the moment but I''m not sure about this problem. Do I assign each user a new TCP/IP Port or do I bundle them all through one port?

Share this post


Link to post
Share on other sites
im newb at networking so dont take this as certain, but you probably could put all users/players thru one port I think this is what most games do now. Ports do not have a bandwidth only the connection. You may however want to have a different port for joining to prevent DOS attacks (I dont know if this will work but i remember reading something about using UDP to prevent DOS attacks) Ports simply accept packets of data. The source information is encoded in the header so you can simply find out where its from using the source ip. I know hardly anything about Winsock so dont ask me . Someone else can tell u about that. I hope this helps (and is not complete crap).

Share this post


Link to post
Share on other sites
An IP port is essentially one connection. What happens when you accept an external connection, is that it moves that connection onto a new port, freeing up your listening port again. Generally you don''t need to worry about what port you''re using for accepted connections as the OS picks a random unused one for you. You just keep 1 port open as a listening socket (assuming you''re running a ''server'') and the API calls do the rest (until you want to do complex stuff).

Share this post


Link to post
Share on other sites
that''s sort of like what I''m doing now...

I''m basically having a main listening port which people connect to. This port does very little except for send the user a dedicated port number for them to use and then the client program reconnects to that port and then the server starts questioning them. That way each user is connected to the server on their own port.

However, as _Stinger said, I should perhaps be making every one come through one port in which case I''m going to need to modify my API calls a little.

Is there any disadvantage to using loads of ports rather than just one if my server is going to be entirely dedicated to one application?

Share this post


Link to post
Share on other sites
Some things have been mixed up here...

A port is a way of naming a machine. If you compare it to the RL mail system, the IP address would be the house the receiver lives in, while the port number would be the name of receiver.

So basically, you can have as many connections on a single port as you want, but youo can only have a single connection between a pair of IP/port-addresses. If you have bound to port :80 of your machine, you can server as many connections as you want, but you can''t have two connections to 24.23.22.21:1156 at the same time.

The other issue are sockets. Sockets are the way OSs present net connections to the programmer. The rule for TCP/IP-sockets is:
One socket is either unconnected, in listen-mode, or connected to exactly one peer. Now if you want to listen, you can only bind() a single socket to a port. However, as soon as you accept() a connection, the socket is cloned: the original socket is still listening on that port, while the new socket is your handle to the connection. Both sockets use the same port though.
Now if you start a connection, you can only have one socket per port due to the way BSD sockets are laid out (at least I think so). However, if you initiate a connection, you usually don''t bind() anyway: in that case, the OS will pick a (more or less) random, unused port for you.

If you''re using UDP, sockets aren''t connected anyway, but the app handles everything that has to do with connections. In a UDP scenario, you usually have a single socket bound to a single port.

So basically, you don''t have to worry about port limitations. What you do have to worry about are socket limitations. For example, in Linux sockets are file descriptors, and the fd limit is somewhere around 250 per process (you can change it with a kernel recompile).

Generally, if you want to write a huge server that is intended to serve a virtually infinite amount of clients (e.g. a master server, or maybe a MMO server - although MMO would fare better with several distributed servers) you''re better off using UDP.

(BTW, I''ve referred to BSD sockets above; WinSock is based on BSD, only the async socket stuff is different, but that isn''t really important for this discussion)

cu,
Prefect

Resist Windows XP''s Invasive Production Activation Technology!
One line of sourcecode says more than a thousand words.

Share this post


Link to post
Share on other sites
Ehh.. I''ve taken so long to write my post that I didn''t see the other reply.

Just have one listen-socket, and use the socket returned by listen() to communicate with the client. Redirecting to another port is completely unnecessary, it might even take up more OS resources - and it''ll introduce potential troubles with firewalls. (You''ll know what I mean if you''ve ever tried to use FTP across a firewall)

cu,
Prefect

Resist Windows XP''s Invasive Production Activation Technology!
One line of sourcecode says more than a thousand words.

Share this post


Link to post
Share on other sites
You see, assuming you''re using TCP, you''re doing extra work that you don''t need to do WSAAccept(), like standard accept(), returns you a new socket to work with. That new socket will already be connected to a new port on your side. Therefore you don''t have to negotiate yet another new one after you''ve called accept() or WSAAccept().

Sequence of actions:

Server opens a port for listening. (Example: port 80).
Client connects to port 80. A random port on the client''s machine is now connected to port 80 on the server.
Server accepts the connection. This tells the client that the connection has been established, and returns a new socket with a new port on the server side. A random port on the server is now connected to that random port on the client side. Port 80 is now free again.
Repeat for each client.

This is accomplished via the listen, connect, and accept commands. (Add a WSA prefix for Winsock.)

Share this post


Link to post
Share on other sites
Cheers...that cleared quite a few things up.

So let me recap too see if I''ve got this right....

So first I begin by setting up a socket to listen and do this by
1. Make a socket
2. Bind the socket to the adapter on one port i.e. 80
3. and then set that socket to listen...
4. and make an event when someone connects to that socket...(WSAAsyncSelect does this I think)

then someone connects.....

5. we accept the connection using accept passing the socket that is bound to the port in 2. and it returns a clone of this socket.
6. Then I send messages using this new socket for a parameter in the SocketSend API call...

then someone else connects....

7. and the oldest socket is still bound to the adapter and I get another clone of that but this time it refers to someone else...

is that right?

Share this post


Link to post
Share on other sites
That''s what you need to do IF you want TCP connections - which you generally don''t for a game :p.

A TCP connection requires 3 sockets to create a connection. A UDP connection requires 2, one socket (total) on the server, and one socket on each client. Every client sends data to the same port on the server. So long as no hacker is doing anything underhanded, every packet received will identify the sender.

There are TCP ports and UDP ports. Considering that each socket gets about 32k for it''s packet buffer, UDP offers considerable memory savings for mmog''s (since you only need 1 server socket, instead of one server socket / client).


Port do sorta have a bandwidth limitation, I''m not sure what happens if a packet is received and the packet buffer is full, it''s probably dropped... which would severely affect the transfer rate.


Magmai Kai Holmlor
- Not For Rent

Share this post


Link to post
Share on other sites
Well I appear to have got my TCP/IP control sorted after an evening of hard work. It now works PROPERLY! My only quiz is that is there anyway to send extended data with WSAAsyncSelect()? I''m using this to notify my application of a connection, or data arrival. However, at the moment I''m using an array of text boxes for the hwnd parameter in order to identify which socket is sending this data. There seems to be no way to add send parameters with the message, nor to work out which socket raised the message. At the moment I''m identifying it by the array Index which cannot be good...!

UDP eh....I did think about this but it didn''t really seem like anyone much used it. However, since you recommend it I might take a trip around the tutorials to find out about it!

Share this post


Link to post
Share on other sites
quote:
Original post by live_time_ex
UDP eh....I did think about this but it didn''t really seem like anyone much used it. However, since you recommend it I might take a trip around the tutorials to find out about it!


The reason for this is that most books on game programming seem to throw in networking as an "afterthought". The networking for a commercial game these days will likely be written by a "Network Programmer", not necessarily a "game programmer". The majority of books that cover any networking make comments like "UDP would normally be used, but since this is just a tutorial, we''ll use TCP/IP." For a reasonable implementation using UDP check out Advanced 3D Programming with DirectX by Adrian Perez (Dan Royer wrote the networking section...).

Honestly, my advice to newbies would be to write several TCP/IP based apps to get familiar with the API calls before jumping into UDP. You should also have some experience with data structures(queues and lists) and memory management.

Share this post


Link to post
Share on other sites
Kylotan: That''s not correct. While it doesn''t change the situation for the programmer, the server _does not_ allocate a new port for an incoming connection (it does assign a new socket, but that''s a different thing). If you don''t believe me, check out the TCP RFCs, or (a bit easier ) check out netstat -a -n while surfing etc... all your HTTP connections will go to port :80 on the server side (and an arbitrary port number on the client side, i.e. your computer; Windows usually assigns port numbers sequentially, starting with 1025 IIRC).

live_time_ex: UDP is generally better with games, though I guess it might be better if you get a feeling for TCP first, as it''s quite a bit easier. However, DON''T use TCP for games (well, it''s OK for MUDs ). I also don''t like the idea of anyone using (and getting used to) the WSAxxxx functions, as they''re Winsock-specific, and will greatly reduce the portability of your game / program. Using BSD-like functions (i.e. WinSock-functions without WSA) works just as well.

cu,
Prefect

One line of sourcecode says more than a thousand words.

Share this post


Link to post
Share on other sites
quote:
Original post by Prefect
Kylotan: That''s not correct. While it doesn''t change the situation for the programmer, the server _does not_ allocate a new port for an incoming connection (it does assign a new socket, but that''s a different thing).

Sorry: I think I was thinking of file descriptors rather than ports. (The sockets are just file descriptors on most non-Windows platforms anyway.)

Share this post


Link to post
Share on other sites
I don''t know if they share the buffer. It prolly depends on the implementation and OS anyway...
However, it''s likely that each socket has its own buffer. For example, some IRC servers can have up to 4000 clients connected at the same time, and those 4000 clients all use the same port. If they all shared the same packet buffer, you''d get lots of buffer overflows, so...

cu,
Prefect

One line of sourcecode says more than a thousand words.

Share this post


Link to post
Share on other sites
I''m not a complete newbie...I''ve been working on computer games for about 10 years now...

I am however new to network programming....call it educational enrichment!

I''m basically going to mess around with TCP/IP for a bit and hack together a basic working chat system and mess around with that...maybe network a simple game that doesn''t require too much data....

then I''ll move onto UDP...

What''s DirectPlay like to program? Loads of people seem to be pushing that in my direction. I guess it''ll have a maximum number of players allowed in one game (at a guess 64?).

Anyway...thanks for everyone''s help here...i''ve learnt an incredible amount over the last couple of days!





Share this post


Link to post
Share on other sites
Hi Prefect. I just want to take a moment to thank you for your most enlightening posts. I''ve been having some problems understanding the relationship between sockets, ports, binding, accepting, etc. And you cleared it all up.

Thanks!

Now if you could help me understand the next step, I would be grateful. How do I handle multiple connections? Since the accept function is blocking, do I need to run a separate thread to accept additional clients? Or is there a nonblocking version of accept?

If anyone could point me out to some easy to understand code examples, I would appreciate it. Thanks!

BTW Prefect, could you please recommend some books that you found most helpful?

quote:
Original post by Prefect
Some things have been mixed up here...




Share this post


Link to post
Share on other sites
I''m not Prefect, but I can help a bit here. Traditionally the way in which you handle multiple connections is with the ''select'' function. You call select and it populates a little structure that tells you which of the specified sockets have some data waiting on them. Select waits as long as you like (you pass it a time value) and when it returns, you know exactly which sockets you can read or write from. (It also tells you which sockets have raised exceptions, although I have never found a use for that, yet. I just call shutdown and close on such sockets, should it ever arise.) This way, you know you can safely call your read or write operations knowing that there is data ready and therefore it shouldn''t block. Your listening socket is just another socket as far as select is concerned, and when there''s data waiting to be read on it, that means you can call accept safely. On all other sockets, you probably want to call read or recv or whatever it is.

Note that some people say select is not such a good function for reasons I don''t entirely understand, since I am no networking expert. But it is portable and well-understood. There are other ways of doing what you want, but I think they mostly tend to vary from platform to platform.

Share this post


Link to post
Share on other sites
Yea, that''s basically it.

And there really is no reason why you might want anything but select(). You could, of course, argue that realtime games have busy loops where timeouts aren''t wanted. But then, calling select() with a timeout value of 0 should work just fine

If you still don''t want to use select(), you should set your sockets to non-blocking with something like this:

#ifdef _WIN32
{
unsigned long arg = 1; /* activate non-blocking */
ioctlsocket(listen_sock, FIONBIO, &arg);
}
#else
fcntl(listen_sock, F_SETFL, fcntl(listen_sock, F_GETFL) | O_NONBLOCK);
#endif

... where listen_sock is your socket. When a socket is non-blocking, calls like recv(), accept(), etc... will always return immediately. recv() will return 0 (no data read), accept() and some others will return -1 (i.e. error) with errno set to EAGAIN (which is an alias for EWOULDBLOCK).

BTW, on some Unices there''s poll() as an alternative to select(), but it''s not as widely supported as select(), and I don''t really see its advantages.

cu,
Prefect

One line of sourcecode says more than a thousand words.

Share this post


Link to post
Share on other sites
Thanks Kylotan and Prefect!

Select() sounds good. Is the blocking recv() the only other function i have to worry about?

Also, can I just get away with calling recv() with the MSG_PEEK flag in an if statement:

SOCKET socket;
char buffer[32];

if (recv(socket,buffer,32,MSG_PEEK) == 32)
recv(socket,buffer,32,0);
continue with game loop....

Some more questions.
Should the server listen every frame?
Should clients send on every frame?
How large should I make the buffer for the recv statement? Just enought to hold 1 packet?


I''m just doing a very simple networked realtime demo with some moving player-controlled balls. So all I''m sending back and forth are position packets.

THANKS!

quote:
Original post by Prefect
Yea, that''s basically it.

If you still don''t want to use select(), you should set your sockets to non-blocking with something like this:

cu,
Prefect

One line of sourcecode says more than a thousand words.


Share this post


Link to post
Share on other sites
I think you misunderstood a little: the whole idea of select() is that you no longer need to worry about something being blocking. It gives you a list of all the sockets that have data waiting. If there is data waiting to be read, then you can call recv and it will read that data and return. The only time these calls will give you trouble, is if you try calling them on a socket that has no data. select tells you which ones have data so you no longer have that problem. No need to ''peek''.

Share this post


Link to post
Share on other sites
Not to mention that MSG_PEEK is evil in high performance applications.

quote:

Prefect wrote:
Yea, that's basically it.

And there really is no reason why you might want anything but select(). You could, of course, argue that realtime games have busy loops where timeouts aren't wanted. But then, calling select() with a timeout value of 0 should work just fine



I'm sorry Prefect, it looks like we will not agree on this subject I think you once mentioned that you program on *nix and haven't done much programming on Windows. Under Windows, select() and WSAWaitForMultipleEvents is limited to 64 handles. While this can be increased be redefining the FD_SETSIZE parameter the call then becomes non-portable and inefficient.

Try creating 2000 sockets and calling select() on them using 1 thread. If this ends up being more efficient than an overlapped I/O call (and especially an I/O completion port call) then I'd be amazed and eat my shorts Even under *nix I understand that they are trying to add the I/O completion port model because it is so effective.

Now, if you are not looking to maximize the efficiency of your server or want a lazy-mans way of porting (just my opinon), then use select().
In my opinion the proper way is to write a portable framework that abstracts the notion of socket i/o from socket descriptors and socket operations. Then you write an implementation for *nix using whatever method you want and a version for Windows using overlapped I/O (and overlapped I/O + I/O completion ports under NT/2000).

So what I'm trying to say is that there are very good reasons for not using select() under Windows.

Still, I'll concede that maybe in this instance, for someone just learning about non-blocking sockets select() would indeed be easier and more portable.

Just my two cents,

Dire Wolf
www.digitalfiends.com

Edited by - Dire.Wolf on August 23, 2001 1:14:04 PM

Share this post


Link to post
Share on other sites
quote:
Original post by Kylotan
I think you misunderstood a little: the whole idea of select() is that you no longer need to worry about something being blocking. It gives you a list of all the sockets that have data waiting. If there is data waiting to be read, then you can call recv and it will read that data and return. The only time these calls will give you trouble, is if you try calling them on a socket that has no data. select tells you which ones have data so you no longer have that problem. No need to ''peek''.


Thanks! I was worried that the file descriptor may be set for read, but the socket could be partially filled with the data i''m expecting. So I thought I should peek just to make sure my entire packet got there.

On second thought, I suppose the reliable nature of TCP would guarantee that.

Share this post


Link to post
Share on other sites
TCP doesn''t support discreet messaging. It is a stream based protocol. If I send you 4 packets of 32 bytes, on the receiving end you may end up with one 128 byte chunk of data. Calling recv() returns whatever is in the buffer. UDP is a bit different because it supports message transmission. Using the same example above you''d receive 4 packets of 32 bytes.

One easy way to have TCP support message sizes is to include a header in the data you send. This header contains the length of the packet.



Dire Wolf
www.digitalfiends.com

Share this post


Link to post
Share on other sites
quote:
Original post by Edwin Park
I was worried that the file descriptor may be set for read, but the socket could be partially filled with the data i''m expecting. So I thought I should peek just to make sure my entire packet got there.

As stated, TCP doesn''t send packets (at least, not that the end programmer can see) and all it can guarantee in this case is that there is something for you to read. If you call recv and don''t get as much data as you were expecting, you buffer it and append to that buffer next time.

Share this post


Link to post
Share on other sites