On a Z80, there's a pin on the chip that is asserted (set to the high or logical 1 state) when the instruction is an IN or OUT instruction. The hardware connected to the chip monitors that pin, plus the Read/Write pins, plus some of the address pins, to determine whether the operation refers to them. Each device is configured to recognize some number as their port number and to respond accordingly. So, when you write an assembler instruction such as:
the chip sets the low-order 8 address pins to 15 and writes the contents of register A to the data pins. If the hardware is configured and connected properly, it knows that is intended for it. Similarly with
With memory mapped I/O, there is a memory location reserved for the hardware. When the CPU writes to address 0xFFF0, say (assuming a convenient 8-bit micro-architecture such as the the 6502 or 6800 or 6809 - or, indeed, Z80), then the hardware connected to respond to that address is not a RAM chip but the device. Typically, there is at least one nearby address that is used for reading; sometimes, the same address is used for both read and write.
In both cases, the issue is basically that the hardware connected to the CPU recognizes certain patterns of activity on the chips pins (some control pins, the data pins and the address pins) as referring to them. You can run into problem if several different devices all think the same address or I/O port refers to them.
Although I've used 8-bit chips for the examples, the same basic principles apply to 16-bit, 32-bit or 64-bit chips.