I've seen it commonly repeated the object oriented programming is based on modelling the real world, but is it?
It seems to me that is not true of anything outside of the business layer.
No. As you point out, many of the things "modeled" in an OOP language are abstract concepts like message queues and controllers and stacks.
Even in your business layer, you're still not modeling "the real world". Assume you have an employee class. Employees are also People, who are also Mammals, who are also Animals, who are also… (yawn) Employees have favorite colors, and they wear certain clothes and believe certain things. In short, there's a huge range of complexity in the real world that we don't even attempt to capture in most programs.
In modeling, we only focus on the aspects of the model that are meaningful to the task at hand. If we're designing a time entry system, then we probably want some sort of Employee class, but that class doesn't need a property to express the employee's favorite color.
Therefore, models shouldn't attempt (or pretend) to completely represent the "Real World".
While some objects I create are modelling real world objects, would not pre-OOP code do the same? I doubt that OO was the first people to include concepts like Customer in their code bases.
You are correct. If you look at large programs that are not OOP, they are often still organized around data structures. A data structure and all of the functions that manipulate are defined near each other, for clarity reasons. (The subversion project is a good example of this. Data structures and functions are prefixed with module names so that it's clear which structures and functions are intended for use with each other.)
I'm no expert on the history of programming languages, but I imagine that OOP grew out of the casual observation that code was clearer and easier to understand when it was organized this way, so language designers started designing languages where that type of organization was more strictly enforced.
The biggest difference between OOP and non-OOP is that OOP binds code to data. So rather than calling code like this:
we do this instead:
Although this may seem like a grammatical difference, the difference is actually in mindset. We tell objects what to do, and typically don't care what the internal state or workings of the object are. When describing an object, we only need to describe it's public interface in order to work with it.