Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

Dark GDK / Winsock Questions (newbie)

Author
Message
Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 10th Apr 2008 20:56 Edited at: 10th Apr 2008 20:57
Oh my god. I am so stupid! I forgot that a few years ago I'd forwarded some random ports to an old IP on my router, which happens to be unused now as it is 192.168.1.4. These port forwards were over-riding the 'virtual server' mode I was using. I just ran a test with the server on my computer and client on someone else's who lives near me, and it now works after removing those dud port forwards.

So much time wasted trying to figure out something so simple.. Urgh... *hits self*
Lilith
16
Years of Service
User Offline
Joined: 12th Feb 2008
Location: Dallas, TX
Posted: 10th Apr 2008 21:04
Glad you got if figured. It's the same problem I have when trying to help one of my users. Without knowing what they've done and they not recognizing that they've done anything it becomes hard to determine the problem from afar.

Lilith, Night Butterfly
I'm not a programmer but I play one in the office
Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 17th Apr 2008 19:09 Edited at: 17th Apr 2008 20:16
I've done some more work with UDP setting up a server that accepts multiple connections from several clients. When a client uses the 'connect' command after the server has set up a socket for that client only to use, packets sent are received by the listening socket on the server but not the socket that was set up for use with the client.

Here is the way the connection process is being carried out at the moment:
-Server begins by setting up a listening socket, binding it to local address and setting it to non blocking mode.
-Client begins by setting up a main socket, binding it to local address and setting it to non blocking mode.
-Client sends a unique code (e.g. "1234") to the server using the 'sendto' command and waits for a reply.
-Upon receiving a message with this unique code on the listening socket, the server sets up a socket for communication with that client alone. We can call this socket 1.
-Socket 1 has address reuse enabled, is bound to the local address and set to non blocking mode. It is then associated with the client's remote address using the 'connect' command.
-Socket 1 then sends the unique code to the client.
-When the client receives this unique code, it associates itself with the server using the 'connect' command.

As mentioned earlier, the problem is that after all this, the server receives packets on the listening socket instead of the udp socket assigned to the client.

Does this mean that the server needs to assign a separate port per client or is there a way of specifying which socket a client can use?

[EDIT] Perhaps having everything received by the server on one socket isn't a problem? Certainly from the programming end of things, its much easier to receive on one socket than multiple ones
jason p sage
17
Years of Service
User Offline
Joined: 10th Jun 2007
Location: Ellington, CT USA
Posted: 18th Apr 2008 02:23
your app needs to handle them all regardless... so one "socket" or many may or may not matter - but I'm not posting to state this either way - I'm posting because I read your post and thought you were describing and coming to the conclusion - that different ports are in order.

I am pretty sure that a if you have one nic card, all you have left are ports.

TCP Adress to me is an "Area Code and Phone Number" and the port is the "Phone Extension"

Benjamin
21
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 18th Apr 2008 03:02
You can't use multiple ports really. If the server replies on a different port, the client's router or firewall may block it.

Anyway, I'm not sure what the problem could be, but I'll do some experimenting and get back to you.

Benjamin
21
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 19th Apr 2008 06:56
I've spent a couple of hours writing a couple of applications only to come to the conclusion that it's not possible to do this.

I assumed that when a UDP socket is associated with a particular remote address, the system will deliver data to this socket with a higher priority than a socket that has no particular remote association, but this isn't so - it seems to just deliver the data to whichever socket it prefers. This is rather disappointing. Sorry for the wasted time.

Instead you'll have to use a single socket, and check the address each time to find out who it was from.

Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 19th Apr 2008 17:52
Thanks again for your help

Quote: "it seems to just deliver the data to whichever socket it prefers"


On the server, does this mean that I need to check the assigned UDP socket as well as the listening socket just in case it decides to start receiving data on that rather than the listening socket?
Benjamin
21
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 19th Apr 2008 20:04
To be honest I think you'd be better off just using a single socket. It saves the hassle of having to manage multiple sockets for a single client.

Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 19th Apr 2008 21:07
So: instead of setting up a socket for each individual client, I should just keep records of clients address information and use the 'sendto' command to send to each one via a single main socket on the server? On the server there is now only ever one socket that receives and sends to clients?
Benjamin
21
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 19th Apr 2008 22:06
Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 23rd Apr 2008 18:35
UDP all seems to be working Now for TCP..

Should I be having 2 sockets now, one for UDP and one for TCP?
Will there be any problems where UDP data is read by a TCP socket and visa versa or does winsock automatically receive data on the correct socket depending on its socket type?
jason p sage
17
Years of Service
User Offline
Joined: 10th Jun 2007
Location: Ellington, CT USA
Posted: 23rd Apr 2008 18:42
Feel like my credibility is shot here - as I learned alot about udp from peering in here. But, I'd personally separate them for the mere "modular" separation.

TCP I know more about. The request comes in, you then set up the "conversation" on a different Port. That' show my web server works. Any port can be used, default for http is obviously 80, but "Web Requests" come in on 80, then the server sets up a tcp connection with the "requester/client" , on whatever port it wants, and sends the reply, then closes the connection.

Benjamin
21
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 23rd Apr 2008 18:51
You can't read UDP data with a TCP socket and vice versa. If you send a UDP packet to a machine, the system will only deliver it to a UDP socket. TCP and UDP port ranges are independent of each other.

jason p sage
17
Years of Service
User Offline
Joined: 10th Jun 2007
Location: Ellington, CT USA
Posted: 23rd Apr 2008 19:03
Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 23rd Apr 2008 19:18 Edited at: 23rd Apr 2008 19:21
Quote: "TCP and UDP port ranges are independent of each other."


Does this mean that the TCP and UDP socket should be able to have the same port and work fine?

When I add the following line of code to the server, it stops picking up any UDP packets from the client; although, it can still send UDP to the client with no problems. Both sockets are running on the same port:


[edit] Here is the code responsible for setting the socket's information. The WinsockError function simply checks for errors:
Benjamin
21
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 23rd Apr 2008 19:19
Quote: "Does this mean that the TCP and UDP socket should be able to have the same port and work fine?"

Yes.

As for the issue, I have no idea what the problem could be.

Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 23rd Apr 2008 20:28 Edited at: 23rd Apr 2008 20:28
I seem to have solved the problem. I moved the tcp 'listen' command to occur before the udp 'recvfrom' command each loop, rather than after and now everything works fine

With TCP, does each connected client have to have its own socket whilst there is one main listening socket to check for incoming connections? Basically, is TCP coded in a similar way to how we were originally trying to code UDP?
Benjamin
21
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 23rd Apr 2008 20:33 Edited at: 23rd Apr 2008 20:34
Quote: "With TCP, does each connected client have to have its own socket whilst there is one main listening socket to check for incoming connections?"

Correct, you use the accept function to have an incoming connection attempt accepted and a socket created for it.

Quote: "Basically, is TCP coded in a similar way to how we were originally trying to code UDP?"

TCP is much simpler.

Lilith
16
Years of Service
User Offline
Joined: 12th Feb 2008
Location: Dallas, TX
Posted: 23rd Apr 2008 20:35
I don't have any heavy experience in this area but my understanding is that when dealing in an multi-connection application the server should negotiate a unique socket for each client it's talking to. I'm assuming each socket assigned to it's own thread. The port number remains the same but the socket information in each subsequent packet tells the server, somehow, which thread to hand it off too. I'm sure that's a programmer's issue.

Same port, different socket for each connection.

Lilith, Night Butterfly
I'm not a programmer but I play one in the office
Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 24th Apr 2008 00:02
New question: Is there a way that I can declare winsock structures and normal C++ structures dynamically so that I don't have to set the maximum number of clients using a constant?
Lilith
16
Years of Service
User Offline
Joined: 12th Feb 2008
Location: Dallas, TX
Posted: 24th Apr 2008 00:10
You can use the new keyword to dynamically allocate memory and reallocated it. But because you're likely to be using threads it wouldn't be a safe thing to expand the size since this usually requires setting a new section of memory aside, copying the contents of the old to the new and reassigning the pointer.

A std::vector may work. But I couldn't swear to it. I'm not sure if the memory locations would remain stable. Probably the best way to go would be to use a doubly linked list. There may also be a way to create a class object for each new thread you want to run that contains the incident data.

Just bear in mind that you still have memory limitations and need to check for enough memory to create new objects

Lilith, Night Butterfly
I'm not a programmer but I play one in the office
jason p sage
17
Years of Service
User Offline
Joined: 10th Jun 2007
Location: Ellington, CT USA
Posted: 24th Apr 2008 01:11
Quote: "There may also be a way to create a class object for each new thread you want to run that contains the incident data"


THAT is how I did my homebrew web server (not online BTW... needed SLL .. might switch back to it now though) its faster than apache, iis, lighttp, so I am bias for this particular recommendation... though might not be appropriate for udp.

I PREALLOCATE a configurable number of threads... and each new web request gets one, serves the file, closes the connection, logs what just happened, and resets for another go.

Benjamin
21
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 24th Apr 2008 08:24
Quote: "Is there a way that I can declare winsock structures and normal C++ structures dynamically so that I don't have to set the maximum number of clients using a constant?"

Yes, though the method you will want to use depends on how you need to access the data. Have a look at STL for some classes that can handle this.

Just remember that if you are using threading (which I would recommend, at least one separate thread for networking should be sufficient) then you'll need to use some form of synchronization such as critical sections. Threading and synchronization themselves are a whole different topic, so you may want to jump into that world separately before you do any networking coding with it.

Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 24th Apr 2008 09:32
Thanks for all your help everyone; I'll have a look at all this later today.

New Question: Roughly how is encryption of packets achieved?
Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 24th Apr 2008 17:17 Edited at: 24th Apr 2008 17:19
I've done some reading on I/O methods and I'm looking into Overlapped I/O; I just want to check that my understanding of how it works is correct (below talking about sockets using the I/O method):

-WSARecv and WSASend point the socket to a buffer and tell it to receive/send to this buffer when ready. The commands themselves return instantly and simply indicate whether the socket was pointed successfully but do not indicate if the receive/send process itself actually succeeded.

-When sending using the WSASend command, the buffer supplied is cleared when the actual send has occurred and so this is how we determine if actual sending succeeded.

-When receiving using the WSARecv command, the buffer supplied is filled and this is how we determine if the actual receiving succeeded.


Also:
I don't understand the purpose of threads. What are their advantages and when should they be used?

Is 'Overlapped I/O' only useful when dealing with multiple sockets as we are doing with TCP?
When it comes to UDP am I right in thinking that Overlapped I/O isn't relevant because we are simply using 'recvfrom' and 'sendto' on a single socket.
Lilith
16
Years of Service
User Offline
Joined: 12th Feb 2008
Location: Dallas, TX
Posted: 24th Apr 2008 17:46
Quote: "I don't understand the purpose of threads. What are their advantages and when should they be used?"


When you kick off a program Windows allocates a thread to your application. This is what allows Windows to parcel out time for your application to run along side the other applications that are running on your workstation. Within a thread Windows provides the messages necessary for your program to receive instructions regarding input or changes in the environment and allows time for your program to react to these messages. If you're going to do something that's work intensive you probably want to kick off another thread to handle that task while your application is allowed to react to its own needs.

Example: I wrote an application a couple of years ago the purpose of which was to drill down through a massive folder structure with hundreds of thousands of files inside and accumulate data as to how much space was being taken up in each folder and how many files fit in certain size ranges. As you can imagine, this isn't something that was going to take a second to do. But I started the process anyway. What happened was that although the process ran, it kept all the application activity in that tight loop. The rest of the application wasn't able to react to requests to minimize the application, move it around or even shut it down. That's because my loop was preventing the application from reacting to messages from Windows.

The solution was to create another thread (a worker thread) to do the work in the background. This is typically done by creating a pointer to the thread process and assign it while calling a process that launches the secondary thread. The process that launches the thread should require the address of a function that will run in the thread and a void pointer to data to be passed to that function. Ideally the function won't do any GUI of it's own, just do the work. Having this second thread running give the application the ability to receive messages from the original thread so it can react to messages from the OS.

Running a worker thread may require a bit of ingenuity on your party, especially if you need to communicate between the worker thread and the main thread. This pertains mostly to situations where both threads (and you may need to use more than one additional thread) need to write to shared data. You have to take steps to create locks on the data so that one thread doesn't change it while another thread thinks it's changing it. This normally utilizes a mutex to help lock data so only one process can access it. I've found this isn't as necessary if one process need to write the data while the other only needs to read it. I've had to use this method to tell a thread to shut itself down by testing for a boolean value periodically.

I've also run into problems with what I perceive as differences in the way threads run under normal Windows and under .NET. It may also be a difference in C#, but getting to shared data may take a lot more effort in the .NET environment. Another instance of protecting a programmer from him/herself?

Lilith, Night Butterfly
I'm not a programmer but I play one in the office
Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 24th Apr 2008 19:44
Thanks, I think I understand now. I have a few more questions though

-How do I tell CPP what code to execute in each thread?
-Are there any dangers in using threads? (I read somewhere that there were)
-The 'listen' and 'accept' commands have confused me a little. Is the listen command just setting the socket to listening mode or does it need to be called each loop in conjunction with accept. How do I tell if a connection request has been received?
jason p sage
17
Years of Service
User Offline
Joined: 10th Jun 2007
Location: Ellington, CT USA
Posted: 24th Apr 2008 20:06
Quote: "I've found this isn't as necessary if one process need to write the data while the other only needs to read it. I've had to use this method to tell a thread to shut itself down by testing for a boolean value periodically"


I do these tricks alot, sometimes I add a busy flag... serves as a light weight mutex.... If he situation calls for it and application speed would benefit from not having thread locking via mutex - I'll set up read only and write only fields on each side - thread1 and thread2, and manage like full duplex modems. Works great.

Got into a long discussion with people here about this - and one thing I do know well - (from writing OS's from scratch) is how cpus, caches, registers, machine code, system bus signals, and memory addressing is acheived. You NEVER - even in a quad-quadcore system need to worry about more than one thread accessing ANY ENDIAN SIZED ALIGNED MEMORY Address at one specific clock cycle time.. EVER! (That's why that works LILITH!

This gets dicey and messy REAL fast though if you don't know what you're doing, in which case - MUTEX's are ideal. Sometimes YOU MUST use a MUTEX regardless - It all depends on what the data is. To guarantee delivery of a specific value... (versus something like a speedometer where the values are in constant flux) you want a mutex to guarantee you deliver the bytes you meant, and you can get an acknowledment of sorts to guarantee delivery.

Benjamin
21
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 24th Apr 2008 20:19
My suggestion would be to use I/O ports in conjunction with overlapped I/O. You can queue buffers for sending and receiving using WSASend/WSARecv, then when the operation completes a completion packet is sent to the completion port, which can be obtained using GetQueuedCompletionStatus.

Quote: "-When sending using the WSASend command, the buffer supplied is cleared when the actual send has occurred"

No, the buffer is never cleared. You use the GetOverlappedResult function to determine when an overlapped operation completes. The pages on WSASend and WSARecv detail this, so read them carefully.

Quote: "I don't understand the purpose of threads. What are their advantages and when should they be used?"

Threads allow you to asynchronously perform multiple operations at the same time. I would personally say they are most important because they allow you to use blocking, which is when a function waits for an event to occur. Generally you should never constantly poll on a function when waiting for something to occur, as this is a huge waste of CPU time that can be spent doing something else. This is why blocking strategies are so much more efficient. If you use overlapped I/O with completion ports, you can have a single thread block on GetQueuedCompletionStatus and handle every operation that completes (or fails for that matter), while you fire off requests in other threads. While there is no activity, this thread uses zero CPU time.

Quote: "Is 'Overlapped I/O' only useful when dealing with multiple sockets as we are doing with TCP?"

Yes. Using overlapped I/O for a single socket is overkill. In most cases simply using a non-blocking socket is sufficient. Also, you can do overlapped I/O on both TCP and UDP sockets. It still makes sense to use it on UDP sockets because the requirements are still the same - you want to be able to queue multiple sends, and generally you'll definitely want to queue multiple recvs as the volume of activity on that socket will be quite high.

Before you get into this, you should probably research some more. I'm sure there is still a lot you need to understand about using sockets, and trying to learn these things while trying to code something so complex will be quite a headache. I'll give you a couple of examples...

1. Due to the fact TCP is a streaming protocol, when a block of data is sent it isn't guaranteed to arrive all in one piece at the other end. What I mean by this is, the second part of the data may be received at a later time than the first. In fact the minimum amount of data you are guaranteed to receive in one read is a single byte. When coding a message processing algorithm you must remember this. If you use a prefix of two bytes or more for messages to denote the size, never rely on the entire prefix to be received at one time. A partial receive may only occur rarely but in order to code a robust application you must respect this.

2. Handling data that can't be sent at the current time. The default socket buffer size is 8KB. If you issue sends that add up to 8KB, then until the endpoint receives this data any more sends will fail. This is an important consideration.

Lilith
16
Years of Service
User Offline
Joined: 12th Feb 2008
Location: Dallas, TX
Posted: 24th Apr 2008 20:24
Quote: "-How do I tell CPP what code to execute in each thread?"


I'm having a bit of trouble with my old VC6.0 so I'm going largely by memory here. Mind you, this is somewhat indigenous to MFC because it uses their classes.

Build your thread code in a function that's declared as

UINT funct (LPVOID pParam);

The UINT, of course, will be the return type when the function exits. The LPVOID pParam is a far void pointer of pure address. That is, it stores an address of indeterminant type. What you're doing here is passing the address of data of some sort to the function. It's up to the function to cast it to the appropriate type for the specific need. It could be the address of a struct that contains data or even the this pointer of the object initiating the thread. Usually you'll be type casting this value.

Declare a pointer to the CWinThread type.

CWinThread *myThread;

and do

myThread = AfxBeginThread (funct, (LPVOID) &data);

This should kick off funct in a new thread with the address of data passed to it. The rest of the program will continue on from that point. Communication between the application thread and the worker thread is up to you.

Bear in mind that this is very specific to the CWinThread class. Other environments may offer different functionality for this but generally the launching has the same requirements.

Quote: "-Are there any dangers in using threads? (I read somewhere that there were)"


Lots of them. As I mentioned, you need to be careful about the exchange of data between the threads. You need to make sure that you have a way to kill the thread (check out some of the options available to the CWinthread class.) You may run the risk of leaving the thread running even though your application has shut down.

Launching a thread might require you to disable certain functionality in the application until the worker is through so the user can't launch another thread and let things get out of control.

Using functionality developed by others could be dangerous unless they can truthfully say that their class or function is thread safe.

Make sure you know what you're doing with data exchange, if any, between the application and worker threads.

Lilith, Night Butterfly
I'm not a programmer but I play one in the office
Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 24th Apr 2008 21:33
Thanks everyone, I'll spend a while researching some more about networking and threads. For anyone who wants to know more about threads, I found a really good guide here:
http://www.informit.com/articles/article.aspx?p=169479&seqNum=1
Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 15th May 2008 17:29 Edited at: 15th May 2008 17:56
I'm trying to get the WSARecv function to work with TCP, overlapped i/o. Unfortunately I get error 10045 (WSAEOPNOTSUPP) and I can't work out why.

The problem line is:


tcpClientSocket (the socket used) is connected and has the following configurations:


The line of code for setting up the socket is:


Any idea what I'm doing wrong?


[EDIT]
Problem solved, 'flags' was NULL, changed to 0 and now all is well
Michael P
18
Years of Service
User Offline
Joined: 6th Mar 2006
Location: London (UK)
Posted: 28th May 2008 16:36
I have near enough got to grips with some of the basics of i/o but now I'm looking into completion ports. Here is my plan of action; please tell me if this is correct:

1. I only need one completion port to deal with the success or failure of any i/o operations that occur on any of the multiple sockets.
2. This completion port is associated with a single file handle.
3. A single thread is required to continuously call 'GetQueuedCompletionStatus' and deal with the success or failure of i/o operations.

One question I have is: How do I associate an I/O operation such as WSARecv with a file handle so that when it completes a completion packet is sent to the completion port?

Login to post a reply

Server time is: 2024-11-17 15:02:36
Your offset time is: 2024-11-17 15:02:36