You need to write a simple transfer protocol.
Basically you need to come up with a way of one PIC saying to the other: "This is the start of the data, here is the data, and this is the end of the data". That could be as simple as starting and ending your data stream with characters that are identifiable, ideally characters that aren't ever going to be in your data stream, or more complex whereby you have a header describing the data that's about to arrive, and a checksum to ensure that the data was received correctly.
The most understandable (to us) method is to send the data as pure ASCII text, maybe in the form of a hexadecimal string. So for 4 ports you would send 8 characters 0-9A-F followed by a carriage return to mark the end of the data, say a stream like:
017F36AB<cr>
017F36AB<cr>
017F26AB<cr>
017F26AB<cr>
017FA6AB<cr>
etc.
Then it is up to your receiving PIC to decode each character into a 4-bit value, and join together character pairs into a single 8 bit value.
The simplest reception method would be to define an array that is big enough to receive all the characters (8 bytes in this case). As characters arrive, you look to see if it's a character. If it is, then you decode the characters in your array. If it's 0-9 or A-F, then you slide the characters in your array down one space (losing the oldest), then adding the new character in to the top of your array. This is called a sliding window where you have an 8-byte "window" on the data stream that is arriving, and the data "slides" past the window.
A more complex arrangement would be like I wrote for my ICSC Library for Arduino which defines a sending and receiving station (to allow communication between lots of chips), a command, a variable length block of data, and a final checksum. The packet format I came up with is:
(All values are 8-bit and symbolic names are ASCII standard values.)
Preamble:
76543210
+--------+
| SOH |
+--------+
| SOH |
+--------+
| SOH |
+--------+
| SOH |
+--------+
Packet:
76543210
+--------+
| SOH |
+--------+
| DestID |
+--------+
| OrigID |
+--------+
| Cmd |
+--------+
| DatLen |
+--------+
| STX |
+--------+
| Data 0 |
| Data 1 |
| ... |
| Data N |
+--------+
| ETX |
+--------+
| Cksum |
+--------+
| EOT |
+--------+
Checksum is sum of all bytes between (but not including) SOH and ETX, modulus 256.
Special destination address 0x00 is the broadcast. All stations will receive and
act upon messages sent to this address.
Addresses that equate to the ASCII symbols SOH etc should be avoided.
Packet reception and identification is through a 6-byte sliding window identifying
the header of a packet. As bytes arrive they enter the top of the window and
they work their way down to the bottom as more bytes arrive. When the first
byte of the window is SOH, the last byte is STX, and the Dest ID is either 0x00
or the ID of the receiving station, it is assumed a valid packet is arriving.
From this point on DatLen bytes are then read into the data buffer.
If the next three bytes do not equal ETX, the valid checksum, and EOT, then the
packet is rejected. Otherwise the function associated with Command is executed.