private int sendPacket(Packet packet, ClientInfo client) throws ServerNotStartedException, 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(!isRunning) {
				logger.finest("Outgoing packet: could not send because server is not running");
				throw new ServerNotStartedException(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(client.getPacketRecorder()) {
				//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
				client.getPacketRecorder().recordAndAddSequenceNumberToOutgoingPacket(packet);
				client.getPacketRecorder().addReceivedPacketHistoryToOutgoingPacket(packet);
				sequenceNumber = packet.getSequenceNumber();

				try {
					//attempt to send the packet
					byte[] bytes = packet.toByteArray();
					DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, client.getInetAddress(), client.getPort());
					socket.send(datagramPacket);
					if(logger.isLoggable(Level.FINEST))
						logger.finest("Outgoing packet to " + client.getAddress() + ":" + client.getPort() + ":\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
					client.getPacketRecorder().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
					client.getPacketRecorder().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;
	}