There are many kinds of DoS attacks on many kinds of services. The general idea behind most of them is to consume all of some limited resource. If the resource is something critical like memory or network ports, the service becomes unavailable for real work.
These denial of service attacks are difficult to guard against. The simple and extreme solution, not allowing untrusted access to the resource at all, is usually too extreme to be useful. The attacker is merely doing what ordinary clients do, only more so; it is a matter of quantity. It can be hard to place reasonable limits on how much of a resource can be allocated. Also, the architect may not even think of a resource as being limited until too late.
They are also relatively benign, in that the defender can usualy recover completely (by freeing all the resources grabbed, perhaps by shutting down temporarily). It is not like deleting a file or corrupting data, which does permanent damage. Loss of service even temporarily can still be expensive, but sometimes it is cheaper to let it happen and then recover than to try to prevent it. (See SoftSecurity.)
For example, Java has a lot of security infrastructure to prevent various kinds of attacks, but implementations rarely bother to defend against denial of service. E.g. applets are normally prevented from writing to the local file system, so cannot delete files, but they can allocate memory, spawn threads, or open windows, and doing any of these to excess will effectively deny use of the machine. (In the last case, the limited resource is screen real-estate.)
Most defenses are based on some notion of identity. For example, a system might keep back some resources for use only by the superuser, so that at least someone can log onto the system and sort it out. This implies being able to identify who the superuser is. Another example is limiting the resource per user, which fails if an attack is launched under the guise of many different users.
Other popular DoS attacks take advantage of bugs in the way software is implemented. "teardrop" and "winnuke" are two attacks which took advantage of bugs in the way several operating systems reconstructed fragmented packets, causing the OS to crash. Many poorly written servers fail to gracefully handle malformed requests, allowing malicious users to cause them to crash or hang (e.g. almost every "service" from Microsoft had a bug at one time where sending random text would cause it to crash. One popular canned exploit sent the text "Windows NT is the operating system of the future.") These exploits require far fewer resources than resource consumption attacks, making it practical for a person connected to the internet via modem to crash servers with much more available bandwidth and far greater computing power. These are also easily defended against - good coding practices and security review can eliminate most if not all of them, without impacting service to legitimate users.
There's an article at http://www.nwfusion.com/news/2000/0724itrace.html that discusses itrace, a packet traceback system from the InternetEngineeringTaskForce that will allow sysadmins to trace DoS floods back to the source. Salient points:
For more on DistributedDenialOfService? attacks, see http://www.e-gerbil.net/ras/dos.txt, or its wikified [version] on LsecTwiki? (requires security stuff).