private int sendPacket(Packet packet) throws NotConnectedException, NullPacketException, CouldNotEncodePacketException, PacketIOException {
		int sequenceNumber = -1;
		synchronized(CONNECTION_LOCK) {
			//regardless of whether the packet is valid, if the client is not connected then throw a NotConnectedException
			if(!isConnected && !isAttemptingToConnect) {
				logger.finest("Outgoing packet: could not send because client is not connected");
				throw new NotConnectedException(packet);
			}

			//there's no point in sending null packets, so throw a NullPacketException
			if(packet == null) {
				logger.finest("Outgoing packet: could not send because packet is null");
				throw new NullPacketException();
			}

			synchronized(recorder) {
				//add the sequenceNumber, lastReceivedSequenceNumber, and receivedPacketHistory to the packet which we've been
				// recording with our PacketRecorder--also simultaneously record this packet as getting sent
				recorder.recordAndAddSequenceNumberToOutgoingPacket(packet);
				recorder.addReceivedPacketHistoryToOutgoingPacket(packet);
				sequenceNumber = packet.getSequenceNumber();

				try {
					//attempt to send the packet
					byte[] bytes = packet.toByteArray();
					DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, serverInetAddress, serverPort);
					socket.send(datagramPacket);
					if(logger.isLoggable(Level.FINEST))
						logger.finest("Outgoing packet:\n  " + packet.toString().replaceAll("\n", "\n  "));
				} catch (PacketEncodingException e) {
					//encoding issues result when the packet contains connection id or sequence numbers that are out of range.
					// we would not expect these to occur if everything is functioning as normal
					recorder.recordPreviousOutgoingPacketNotSent();
					logger.finest("Outgoing packet: could not send due to PacketEncodingException \"" + e.getMessage() + "\"");
					throw new CouldNotEncodePacketException(e, packet);
				}
				catch (IOException e) {
					//wrapping any IOException the socket might throw so calling send() only throws CouldNotSendPacketExceptions
					recorder.recordPreviousOutgoingPacketNotSent();
					logger.finest("Outgoing packet: could not send due to IOException \"" + e.getMessage() + "\"");
					throw new PacketIOException(e, packet);
				}
			}
		}

		//return the sequence number of the packet that we sent
		return sequenceNumber;
	}